diff --git a/.gitignore b/.gitignore index be15d41..17cfdaf 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/gnome-online-accounts-3.8.5.tar.xz +SOURCES/gnome-online-accounts-3.14.4.tar.xz diff --git a/.gnome-online-accounts.metadata b/.gnome-online-accounts.metadata index 6cba1c5..0356ca8 100644 --- a/.gnome-online-accounts.metadata +++ b/.gnome-online-accounts.metadata @@ -1 +1 @@ -ae9dd4d40004083089650f9571af61c9e9e17ace SOURCES/gnome-online-accounts-3.8.5.tar.xz +1e1364c4ff1446f64fff164153e75f995be1fb22 SOURCES/gnome-online-accounts-3.14.4.tar.xz diff --git a/SOURCES/0001-daemon-Don-t-leak-the-GoaProvider.patch b/SOURCES/0001-daemon-Don-t-leak-the-GoaProvider.patch new file mode 100644 index 0000000..dc6f1bc --- /dev/null +++ b/SOURCES/0001-daemon-Don-t-leak-the-GoaProvider.patch @@ -0,0 +1,33 @@ +From 5e06329c3668da308055e5cd4b75730b45389124 Mon Sep 17 00:00:00 2001 +From: Debarshi Ray +Date: Wed, 27 May 2015 19:01:44 +0200 +Subject: [PATCH] daemon: Don't leak the GoaProvider + +https://bugzilla.gnome.org/show_bug.cgi?id=693578 +--- + src/daemon/goadaemon.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/daemon/goadaemon.c b/src/daemon/goadaemon.c +index 9d5543d..56292b1 100644 +--- a/src/daemon/goadaemon.c ++++ b/src/daemon/goadaemon.c +@@ -1158,7 +1158,7 @@ on_account_handle_ensure_credentials (GoaAccount *account, + gpointer user_data) + { + GoaDaemon *daemon = GOA_DAEMON (user_data); +- GoaProvider *provider; ++ GoaProvider *provider = NULL; + GoaObject *object; + + object = GOA_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (account))); +@@ -1181,5 +1181,6 @@ on_account_handle_ensure_credentials (GoaAccount *account, + ensure_data_new (daemon, object, invocation)); + + out: ++ g_clear_object (&provider); + return TRUE; /* invocation was handled */ + } +-- +2.1.0 + diff --git a/SOURCES/add-smartcard-support.patch b/SOURCES/add-smartcard-support.patch deleted file mode 100644 index a763047..0000000 --- a/SOURCES/add-smartcard-support.patch +++ /dev/null @@ -1,2373 +0,0 @@ -From 0ccab22ee39bd98b63d31c7457d91778b98080bf Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 22 Oct 2014 11:06:19 -0400 -Subject: [PATCH 1/3] kerberos: zero initialize operation structure - -We need zero initialize the structure so we don't end up -freeing unused members when cleaning up the operation. ---- - src/goaidentity/goakerberosidentitymanager.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/goaidentity/goakerberosidentitymanager.c b/src/goaidentity/goakerberosidentitymanager.c -index 7cc90b9..c4da420 100644 ---- a/src/goaidentity/goakerberosidentitymanager.c -+++ b/src/goaidentity/goakerberosidentitymanager.c -@@ -102,61 +102,61 @@ typedef struct - GoaKerberosIdentityManager *manager; - GoaIdentity *identity; - } IdentitySignalWork; - - static GoaIdentityManager *goa_kerberos_identity_manager_singleton; - - static void identity_manager_interface_init (GoaIdentityManagerInterface * - interface); - static void initable_interface_init (GInitableIface *interface); - - static void on_identity_expired (GoaIdentity *identity, - GoaKerberosIdentityManager *self); - - G_DEFINE_TYPE_WITH_CODE (GoaKerberosIdentityManager, - goa_kerberos_identity_manager, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GOA_TYPE_IDENTITY_MANAGER, - identity_manager_interface_init) - G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, - initable_interface_init)); - #define FALLBACK_POLLING_INTERVAL 5 - - static Operation * - operation_new (GoaKerberosIdentityManager *self, - GCancellable *cancellable, - OperationType type, - GSimpleAsyncResult *result) - { - Operation *operation; - -- operation = g_slice_new (Operation); -+ operation = g_slice_new0 (Operation); - - operation->manager = self; - operation->type = type; - - if (cancellable == NULL) - cancellable = g_cancellable_new (); - else - g_object_ref (cancellable); - operation->cancellable = cancellable; - - if (result != NULL) - g_object_ref (result); - operation->result = result; - - operation->identity = NULL; - - return operation; - } - - static void - operation_free (Operation *operation) - { - g_clear_object (&operation->cancellable); - - if (operation->type != OPERATION_TYPE_SIGN_IN && - operation->type != OPERATION_TYPE_GET_IDENTITY) - g_clear_object (&operation->identity); - else - g_clear_pointer (&operation->identifier, g_free); - --- -1.8.3.1 - - -From 8e36b5743bf1e20636a67f406f4937ccc132e50b Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 21 Oct 2014 10:38:17 -0400 -Subject: [PATCH 2/3] ticketing: add new details property - -This commit adds a new "details" variant for attaching metadata -about tickets getting requested via the ticketing interface. - -This will give the kerberos account provider a place to tuck away -kerberos-specific preauthentication configuration for the tickets -associated with smartcard backed kerberos accounts. ---- - data/dbus-interfaces.xml | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/data/dbus-interfaces.xml b/data/dbus-interfaces.xml -index fa4101f..e4d39c4 100644 ---- a/data/dbus-interfaces.xml -+++ b/data/dbus-interfaces.xml -@@ -604,40 +604,42 @@ - - - - - - - - - -+ -+ - - - - - --- -1.8.3.1 - - -From 2cf3c36818fa995791d99c6512b258099cec2879 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 21 Oct 2014 10:46:50 -0400 -Subject: [PATCH 3/3] kerberos: support refreshing smartcard authenticated - kerberos tickets - -Right now gnome-online-accounts doesn't manager smartcard based -kerberos credentials very well. The sign-in button just fails. - -This commit adds support for tickets granted through smartcards. - -Note, at the moment we don't provide a way to add new smartcard -based accounts, merely, manage existing ones that are added implicitly -by logging in with a smartcard, or by explicit kinit. ---- - src/goabackend/goakerberosprovider.c | 43 +++++++++++++++++ - src/goaidentity/goaidentitymanager.c | 2 + - src/goaidentity/goaidentitymanager.h | 2 + - src/goaidentity/goaidentityservice.c | 19 +++++++- - src/goaidentity/goakerberosidentity.c | 71 +++++++++++++++++++++++++++- - src/goaidentity/goakerberosidentity.h | 2 + - src/goaidentity/goakerberosidentitymanager.c | 14 ++++-- - 7 files changed, 146 insertions(+), 7 deletions(-) - -diff --git a/src/goabackend/goakerberosprovider.c b/src/goabackend/goakerberosprovider.c -index 7fe77f6..b125914 100644 ---- a/src/goabackend/goakerberosprovider.c -+++ b/src/goabackend/goakerberosprovider.c -@@ -345,93 +345,100 @@ ensure_object_manager (GoaKerberosProvider *self, - "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); -@@ -513,82 +520,88 @@ on_identity_manager_ensured_for_sign_in (GoaKerberosProvider *self, - - 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, -+ const char *preauth_source, - 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); - g_object_set_data (G_OBJECT (operation_result), - "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; - } -@@ -666,128 +679,141 @@ look_up_identity (GoaKerberosProvider *self, - (GAsyncReadyCallback) - on_object_manager_ensured_for_look_up, - operation_result); - } - - static void - on_account_signed_in (GoaProvider *provider, - GAsyncResult *result, - SignInRequest *request) - { - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), - &request->error)) - { - g_main_loop_quit (request->loop); - return; - } - - g_main_loop_quit (request->loop); - } - - static gboolean - get_ticket_sync (GoaKerberosProvider *self, - GoaObject *object, - gboolean is_interactive, - GCancellable *cancellable, - GError **error) - { - GVariant *credentials; - GError *lookup_error; - GoaAccount *account; -+ GoaTicketing *ticketing; -+ GVariant *details; - const char *identifier; - const char *password; -+ const char *preauth_source; - SignInRequest request; - gboolean ret; - - ret = FALSE; - - account = goa_object_peek_account (object); - identifier = goa_account_get_identity (account); -+ -+ ticketing = goa_object_get_ticketing (GOA_OBJECT (object)); -+ details = goa_ticketing_get_details (ticketing); -+ -+ preauth_source = NULL; -+ g_variant_lookup (details, "preauthentication-source", "&s", &preauth_source); -+ - password = NULL; - - lookup_error = NULL; - credentials = goa_utils_lookup_credentials_sync (GOA_PROVIDER (self), - object, - cancellable, - &lookup_error); - - if (credentials == NULL && !is_interactive) - { - if (lookup_error != NULL) - g_propagate_error (error, lookup_error); - else - g_set_error (error, - GOA_ERROR, - GOA_ERROR_NOT_AUTHORIZED, - _("Could not find saved credentials for principal `%s' in keyring"), identifier); - goto out; - } - else if (credentials != NULL) - { - gboolean has_password; - - has_password = g_variant_lookup (credentials, "password", "&s", &password); - - if (!has_password && !is_interactive) - { - g_set_error (error, - GOA_ERROR, - GOA_ERROR_NOT_AUTHORIZED, - _("Did not find password for principal `%s' in credentials"), - identifier); - goto out; - } - } - - 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); - - if (request.error != NULL) - { - g_propagate_error (error, request.error); - goto out; - } - - ret = TRUE; - out: -+ g_clear_object (&ticketing); -+ - if (credentials != NULL) - g_variant_unref (credentials); - - return ret; - } - - static void - notify_is_temporary_cb (GObject *object, GParamSpec *pspec, gpointer user_data) - { - GoaAccount *account; - gboolean is_temporary; - - account = GOA_ACCOUNT (object); - g_object_get (account, "is-temporary", &is_temporary, NULL); - - /* Toggle IsTemporary */ - goa_utils_keyfile_set_boolean (account, "IsTemporary", is_temporary); - - /* Set/unset SessionId */ - if (is_temporary) - { - GDBusConnection *connection; - const gchar *guid; - - connection = G_DBUS_CONNECTION (user_data); - guid = g_dbus_connection_get_guid (connection); - goa_utils_keyfile_set_string (account, "SessionId", guid); - } - else - goa_utils_keyfile_remove_key (account, "SessionId"); -@@ -831,69 +857,79 @@ build_object (GoaProvider *provider, - GDBusConnection *connection, - gboolean just_added, - GError **error) - { - GoaAccount *account; - GoaTicketing *ticketing; - gboolean ticketing_enabled; - gboolean ret; - - ticketing = NULL; - ret = FALSE; - - if (!GOA_PROVIDER_CLASS (goa_kerberos_provider_parent_class)->build_object (provider, - object, - key_file, - group, - connection, - just_added, - error)) - goto out; - - account = goa_object_get_account (GOA_OBJECT (object)); - - ticketing = goa_object_get_ticketing (GOA_OBJECT (object)); - ticketing_enabled = g_key_file_get_boolean (key_file, group, "TicketingEnabled", NULL); - - if (ticketing_enabled) - { - if (ticketing == NULL) - { -+ char *preauthentication_source; -+ GVariantBuilder details; -+ - ticketing = goa_ticketing_skeleton_new (); - - g_signal_connect (ticketing, - "handle-get-ticket", - G_CALLBACK (on_handle_get_ticket), - NULL); - - goa_object_skeleton_set_ticketing (object, ticketing); - -+ g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}")); -+ -+ preauthentication_source = g_key_file_get_string (key_file, group, "PreauthenticationSource", NULL); -+ if (preauthentication_source) -+ g_variant_builder_add (&details, "{ss}", "preauthentication-source", preauthentication_source); -+ -+ g_object_set (G_OBJECT (ticketing), "details", g_variant_builder_end (&details), NULL); - } - } - else if (ticketing != NULL) - { - goa_object_skeleton_set_ticketing (object, NULL); - } - - if (just_added) - { - goa_account_set_ticketing_disabled (account, !ticketing_enabled); - - g_signal_connect (account, - "notify::is-temporary", - G_CALLBACK (notify_is_temporary_cb), - connection); - - g_signal_connect (account, - "notify::ticketing-disabled", - G_CALLBACK (goa_util_account_notify_property_cb), - "TicketingEnabled"); - } - - ret = TRUE; - - out: - g_clear_object (&ticketing); - - return ret; - } - -@@ -1266,99 +1302,106 @@ on_initial_sign_in_done (GoaKerberosProvider *self, - */ - g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); - g_variant_builder_add (&builder, - "{sv}", - "password", - g_variant_new_string (password)); - - error = NULL; - goa_utils_store_credentials_for_object_sync (GOA_PROVIDER (self), - object, - g_variant_builder_end (&builder), - NULL, - NULL); - } - } - - g_simple_async_result_complete_in_idle (operation_result); - g_object_unref (operation_result); - } - - static void - on_system_prompt_answered_for_initial_sign_in (GcrPrompt *prompt, - GAsyncResult *result, - GSimpleAsyncResult *operation_result) - { - GoaKerberosProvider *self; - GCancellable *cancellable; - GError *error; - const char *principal; - const char *password; -+ const char *preauth_source; - GcrSecretExchange *secret_exchange; - - self = GOA_KERBEROS_PROVIDER (g_async_result_get_source_object (G_ASYNC_RESULT (operation_result))); - principal = g_object_get_data (G_OBJECT (operation_result), "principal"); - cancellable = g_object_get_data (G_OBJECT (operation_result), "cancellable"); - -+ /* We currently don't prompt the user to choose a preauthentication source during initial sign in -+ * so we assume there's no preauthentication source -+ */ -+ preauth_source = NULL; -+ - error = NULL; - password = gcr_prompt_password_finish (prompt, result, &error); - - if (password == NULL) - { - gcr_system_prompt_close (GCR_SYSTEM_PROMPT (prompt), NULL, NULL); - - if (error != NULL) - g_simple_async_result_take_error (operation_result, error); - else - g_cancellable_cancel (cancellable); - - g_simple_async_result_complete_in_idle (operation_result); - g_object_unref (operation_result); - return; - } - - secret_exchange = gcr_system_prompt_get_secret_exchange (GCR_SYSTEM_PROMPT (prompt)); - g_object_set_data_full (G_OBJECT (operation_result), - "secret-exchange", - g_object_ref (secret_exchange), - (GDestroyNotify) - g_object_unref); - - g_object_set_data (G_OBJECT (operation_result), - "remember-password", - GINT_TO_POINTER (gcr_prompt_get_choice_chosen (prompt))); - - gcr_system_prompt_close (GCR_SYSTEM_PROMPT (prompt), NULL, NULL); - - sign_in_identity (self, - principal, - password, -+ preauth_source, - cancellable, - (GAsyncReadyCallback) - on_initial_sign_in_done, - operation_result); - } - - static void - on_system_prompt_open_for_initial_sign_in (GcrSystemPrompt *system_prompt, - GAsyncResult *result, - GSimpleAsyncResult *operation_result) - { - GCancellable *cancellable; - GcrPrompt *prompt; - GError *error; - - cancellable = g_object_get_data (G_OBJECT (operation_result), "cancellable"); - error = NULL; - prompt = gcr_system_prompt_open_finish (result, &error); - - if (prompt == NULL) - { - g_simple_async_result_take_error (operation_result, error); - - g_simple_async_result_complete_in_idle (operation_result); - g_object_unref (operation_result); - - return; - } - - gcr_prompt_set_title (prompt, _("Log In to Realm")); -diff --git a/src/goaidentity/goaidentitymanager.c b/src/goaidentity/goaidentitymanager.c -index b71fb23..8fa7b22 100644 ---- a/src/goaidentity/goaidentitymanager.c -+++ b/src/goaidentity/goaidentitymanager.c -@@ -178,70 +178,72 @@ goa_identity_manager_list_identities_finish (GoaIdentityManager *self, - result, - error); - } - - void - goa_identity_manager_renew_identity (GoaIdentityManager *self, - GoaIdentity *identity, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) - { - GOA_IDENTITY_MANAGER_GET_IFACE (self)->renew_identity (self, - identity, - cancellable, - callback, - user_data); - } - - void - goa_identity_manager_renew_identity_finish (GoaIdentityManager *self, - GAsyncResult *result, - GError **error) - { - GOA_IDENTITY_MANAGER_GET_IFACE (self)->renew_identity_finish (self, result, error); - } - - void - goa_identity_manager_sign_identity_in (GoaIdentityManager *self, - const char *identifier, - gconstpointer initial_password, -+ const char *preauth_source, - GoaIdentitySignInFlags flags, - GoaIdentityInquiryFunc inquiry_func, - gpointer inquiry_data, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) - { - GOA_IDENTITY_MANAGER_GET_IFACE (self)->sign_identity_in (self, - identifier, - initial_password, -+ preauth_source, - flags, - inquiry_func, - inquiry_data, - cancellable, - callback, - user_data); - } - - GoaIdentity * - goa_identity_manager_sign_identity_in_finish (GoaIdentityManager *self, - GAsyncResult *result, - GError **error) - { - return GOA_IDENTITY_MANAGER_GET_IFACE (self)->sign_identity_in_finish (self, - result, - error); - } - - void - goa_identity_manager_sign_identity_out (GoaIdentityManager *self, - GoaIdentity *identity, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) - { - GOA_IDENTITY_MANAGER_GET_IFACE (self)->sign_identity_out (self, - identity, - cancellable, - callback, - user_data); -diff --git a/src/goaidentity/goaidentitymanager.h b/src/goaidentity/goaidentitymanager.h -index 5b60c24..05e6ca8 100644 ---- a/src/goaidentity/goaidentitymanager.h -+++ b/src/goaidentity/goaidentitymanager.h -@@ -54,60 +54,61 @@ struct _GoaIdentityManagerInterface - GoaIdentity *identity); - void (* identity_refreshed) (GoaIdentityManager *identity_manager, - GoaIdentity *identity); - void (* identity_needs_renewal) (GoaIdentityManager *identity_manager, - GoaIdentity *identity); - void (* identity_expiring) (GoaIdentityManager *identity_manager, - GoaIdentity *identity); - void (* identity_expired) (GoaIdentityManager *identity_manager, - GoaIdentity *identity); - - /* Virtual Functions */ - void (* get_identity) (GoaIdentityManager *identity_manager, - const char *identifier, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - GoaIdentity * (* get_identity_finish) (GoaIdentityManager *identity_manager, - GAsyncResult *result, - GError **error); - void (* list_identities) (GoaIdentityManager *identity_manager, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - GList * (* list_identities_finish) (GoaIdentityManager *identity_manager, - GAsyncResult *result, - GError **error); - - void (* sign_identity_in) (GoaIdentityManager *identity_manager, - const char *identifier, - gconstpointer initial_password, -+ const char *preauth_source, - GoaIdentitySignInFlags flags, - GoaIdentityInquiryFunc inquiry_func, - gpointer inquiry_data, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - GoaIdentity * (* sign_identity_in_finish) (GoaIdentityManager *identity_manager, - GAsyncResult *result, - GError **error); - - void (* sign_identity_out) (GoaIdentityManager *identity_manager, - GoaIdentity *identity, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - void (* sign_identity_out_finish) (GoaIdentityManager *identity_manager, - GAsyncResult *result, - GError **error); - - void (* renew_identity) (GoaIdentityManager *identity_manager, - GoaIdentity *identity, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - void (* renew_identity_finish) (GoaIdentityManager *identity_manager, - GAsyncResult *result, - GError **error); - - char * (* name_identity) (GoaIdentityManager *identity_manager, - GoaIdentity *identity); -@@ -117,60 +118,61 @@ typedef enum - { - GOA_IDENTITY_MANAGER_ERROR_INITIALIZING, - GOA_IDENTITY_MANAGER_ERROR_IDENTITY_NOT_FOUND, - GOA_IDENTITY_MANAGER_ERROR_CREATING_IDENTITY, - GOA_IDENTITY_MANAGER_ERROR_ACCESSING_CREDENTIALS, - GOA_IDENTITY_MANAGER_ERROR_UNSUPPORTED_CREDENTIALS - } GoaIdentityManagerError; - - GType goa_identity_manager_get_type (void); - GQuark goa_identity_manager_error_quark (void); - - void goa_identity_manager_get_identity (GoaIdentityManager *identity_manager, - const char *identifier, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - GoaIdentity *goa_identity_manager_get_identity_finish (GoaIdentityManager *identity_manager, - GAsyncResult *result, - GError **error); - void goa_identity_manager_list_identities (GoaIdentityManager *identity_manager, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - GList *goa_identity_manager_list_identities_finish (GoaIdentityManager *identity_manager, - GAsyncResult *result, - GError **error); - - void goa_identity_manager_sign_identity_in (GoaIdentityManager *identity_manager, - const char *identifier, - gconstpointer initial_password, -+ const char *preauth_source, - GoaIdentitySignInFlags flags, - GoaIdentityInquiryFunc inquiry_func, - gpointer inquiry_data, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - GoaIdentity *goa_identity_manager_sign_identity_in_finish (GoaIdentityManager *identity_manager, - GAsyncResult *result, - GError **error); - - void goa_identity_manager_sign_identity_out (GoaIdentityManager *identity_manager, - GoaIdentity *identity, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - void goa_identity_manager_sign_identity_out_finish (GoaIdentityManager *identity_manager, - GAsyncResult *result, - GError **error); - - void goa_identity_manager_renew_identity (GoaIdentityManager *identity_manager, - GoaIdentity *identity, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - void goa_identity_manager_renew_identity_finish (GoaIdentityManager *identity_manager, - GAsyncResult *result, - GError **error); - - char *goa_identity_manager_name_identity (GoaIdentityManager *identity_manager, - GoaIdentity *identity); -diff --git a/src/goaidentity/goaidentityservice.c b/src/goaidentity/goaidentityservice.c -index d51d6bd..b570e09 100644 ---- a/src/goaidentity/goaidentityservice.c -+++ b/src/goaidentity/goaidentityservice.c -@@ -38,60 +38,61 @@ - #include "goaidentityutils.h" - - #include "goakerberosidentitymanager.h" - #include "goalogging.h" - - struct _GoaIdentityServicePrivate - { - GDBusConnection *connection; - GDBusObjectManagerServer *object_manager_server; - guint bus_id; - - GoaIdentityManager *identity_manager; - - GHashTable *watched_client_connections; - GHashTable *key_holders; - GHashTable *pending_temporary_account_results; - - /* FIXME: This is a little ucky, since the goa service - * is in process, we should able to use direct calls. - */ - GoaClient *client; - GoaManager *accounts_manager; - }; - - static void identity_service_manager_interface_init (GoaIdentityServiceManagerIface *interface); - - static void - sign_in (GoaIdentityService *self, - const char *identifier, - gconstpointer initial_password, -+ const char *preauth_source, - GoaIdentitySignInFlags flags, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - - G_DEFINE_TYPE_WITH_CODE (GoaIdentityService, - goa_identity_service, - GOA_IDENTITY_SERVICE_TYPE_MANAGER_SKELETON, - G_IMPLEMENT_INTERFACE (GOA_IDENTITY_SERVICE_TYPE_MANAGER, - identity_service_manager_interface_init)); - - static char * - get_object_path_for_identity (GoaIdentityService *self, - GoaIdentity *identity) - { - const char *identifier; - char *escaped_identifier; - char *object_path; - - identifier = goa_identity_get_identifier (identity); - escaped_identifier = goa_identity_utils_escape_object_path (identifier, - strlen (identifier)); - object_path = g_strdup_printf ("/org/gnome/Identity/Identities/%s", escaped_identifier); - - g_free (escaped_identifier); - return object_path; - } - - static char * - export_identity (GoaIdentityService *self, -@@ -290,151 +291,158 @@ ensure_account_credentials (GoaIdentityService *self, - on_credentials_ensured, - self); - } - - static void - on_sign_in_handled (GoaIdentityService *self, - GAsyncResult *result, - GDBusMethodInvocation *invocation) - { - GError *error = NULL; - - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), &error)) - { - g_dbus_method_invocation_take_error (invocation, error); - } - else - { - const char *object_path; - - object_path = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)); - goa_identity_service_manager_complete_sign_in (GOA_IDENTITY_SERVICE_MANAGER (self), - invocation, - object_path); - } - } - - static void - read_sign_in_details (GoaIdentityServiceManager *manager, - GVariant *details, - GoaIdentitySignInFlags *flags, -- char **secret_key) -+ char **secret_key, -+ char **preauth_source) - { - GVariantIter iter; - char *key; - char *value; - - *flags = GOA_IDENTITY_SIGN_IN_FLAGS_NONE; - g_variant_iter_init (&iter, details); - while (g_variant_iter_loop (&iter, "{ss}", &key, &value)) - { - if (g_strcmp0 (key, "initial-password") == 0) - *secret_key = g_strdup (value); -+ else if (g_strcmp0 (key, "preauthentication-source") == 0) -+ *preauth_source = g_strdup (value); - else if (g_strcmp0 (key, "disallow-renewal") == 0 - && g_strcmp0 (value, "true") == 0) - *flags |= GOA_IDENTITY_SIGN_IN_FLAGS_DISALLOW_RENEWAL; - else if (g_strcmp0 (key, "disallow-forwarding") == 0 - && g_strcmp0 (value, "true") == 0) - *flags |= GOA_IDENTITY_SIGN_IN_FLAGS_DISALLOW_FORWARDING; - else if (g_strcmp0 (key, "disallow-proxying") == 0 - && g_strcmp0 (value, "true") == 0) - *flags |= GOA_IDENTITY_SIGN_IN_FLAGS_DISALLOW_PROXYING; - } - } - - static gboolean - goa_identity_service_handle_sign_in (GoaIdentityServiceManager *manager, - GDBusMethodInvocation *invocation, - const char *identifier, - GVariant *details) - { - GoaIdentityService *self = GOA_IDENTITY_SERVICE (manager); - GSimpleAsyncResult *operation_result; - GoaIdentitySignInFlags flags; - char *secret_key; -+ char *preauth_source; - gconstpointer initial_password; - GCancellable *cancellable; - - secret_key = NULL; -+ preauth_source = NULL; - initial_password = NULL; - -- read_sign_in_details (manager, details, &flags, &secret_key); -+ read_sign_in_details (manager, details, &flags, &secret_key, &preauth_source); - - if (secret_key != NULL) - { - GcrSecretExchange *secret_exchange; - - secret_exchange = g_hash_table_lookup (self->priv->key_holders, - g_dbus_method_invocation_get_sender (invocation)); - - if (secret_exchange == NULL) - { - g_free (secret_key); - g_dbus_method_invocation_return_error (invocation, - GOA_IDENTITY_MANAGER_ERROR, - GOA_IDENTITY_MANAGER_ERROR_ACCESSING_CREDENTIALS, - _("initial secret passed before secret key exchange")); - return TRUE; - } - - gcr_secret_exchange_receive (secret_exchange, secret_key); - g_free (secret_key); - - initial_password = gcr_secret_exchange_get_secret (secret_exchange, NULL); - } - - operation_result = g_simple_async_result_new (G_OBJECT (self), - (GAsyncReadyCallback) - on_sign_in_handled, - g_object_ref (invocation), - g_strdup (identifier)); - cancellable = g_cancellable_new (); - g_object_set_data (G_OBJECT (operation_result), - "cancellable", - cancellable); - g_object_set_data (G_OBJECT (operation_result), - "initial-password", - (gpointer) - initial_password); - g_object_set_data (G_OBJECT (operation_result), - "flags", - GINT_TO_POINTER ((int) flags)); - - sign_in (self, - identifier, - initial_password, -+ preauth_source, - flags, - cancellable, - (GAsyncReadyCallback) - on_sign_in_done, - operation_result); - -+ g_free (preauth_source); - g_object_unref (cancellable); - - return TRUE; - } - - static void - on_sign_out_handled (GoaIdentityService *self, - GAsyncResult *result, - GDBusMethodInvocation *invocation) - { - GError *error; - - error = NULL; - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), &error)) - g_dbus_method_invocation_take_error (invocation, error); - else - goa_identity_service_manager_complete_sign_out (GOA_IDENTITY_SERVICE_MANAGER (self), - invocation); - } - - static void - on_identity_signed_out (GoaIdentityManager *manager, - GAsyncResult *result, - GSimpleAsyncResult *operation_result) - { - GoaIdentityService *self; - GError *error; - GoaIdentity *identity; - const char *identifier; - GoaObject *object; -@@ -846,117 +854,122 @@ on_account_added (GoaManager *manager, - return; - } - - if (object_path != NULL && object_path[0] != '\0') - { - goa_debug ("Created account for identity with object path %s", object_path); - - object_manager = goa_client_get_object_manager (self->priv->client); - object = GOA_OBJECT (g_dbus_object_manager_get_object (object_manager, - object_path)); - g_free (object_path); - } - - if (object == NULL) - g_simple_async_result_set_op_res_gpointer (operation_result, NULL, NULL); - else - g_simple_async_result_set_op_res_gpointer (operation_result, - object, - (GDestroyNotify) - g_object_unref); - - g_simple_async_result_complete_in_idle (operation_result); - g_object_unref (operation_result); - } - - static void - add_temporary_account (GoaIdentityService *self, - GoaIdentity *identity) - { - char *realm; -+ char *preauth_source; - const char *principal; - char *principal_for_display; - GSimpleAsyncResult *operation_result; - GVariantBuilder credentials; - GVariantBuilder details; - GoaObject *object; - - principal = goa_identity_get_identifier (identity); - - object = g_hash_table_lookup (self->priv->pending_temporary_account_results, - principal); - - if (object != NULL) - { - goa_debug ("GoaIdentityService: would add temporary identity %s, but it's already pending", principal); - return; - } - - goa_debug ("GoaIdentityService: adding temporary identity %s", principal); - - /* If there's no account for this identity then create a temporary one. - */ - principal_for_display = goa_identity_manager_name_identity (self->priv->identity_manager, - identity); - - realm = goa_kerberos_identity_get_realm_name (GOA_KERBEROS_IDENTITY (identity)); -+ preauth_source = goa_kerberos_identity_get_preauthentication_source (GOA_KERBEROS_IDENTITY (identity)); - - g_variant_builder_init (&credentials, G_VARIANT_TYPE_VARDICT); - - g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}")); - g_variant_builder_add (&details, "{ss}", "Realm", realm); - g_variant_builder_add (&details, "{ss}", "IsTemporary", "true"); -+ if (preauth_source != NULL) -+ g_variant_builder_add (&details, "{ss}", "PreauthenticationSource", preauth_source); - g_variant_builder_add (&details, "{ss}", "TicketingEnabled", "true"); - - - goa_debug ("GoaIdentityService: asking to sign back in"); - - operation_result = g_simple_async_result_new (G_OBJECT (self), - (GAsyncReadyCallback) - on_temporary_account_created_for_identity, - identity, - add_temporary_account); - g_hash_table_insert (self->priv->pending_temporary_account_results, - g_strdup (principal), - g_object_ref (operation_result)); - - goa_manager_call_add_account (self->priv->accounts_manager, - "kerberos", - principal, - principal_for_display, - g_variant_builder_end (&credentials), - g_variant_builder_end (&details), - NULL, - (GAsyncReadyCallback) - on_account_added, - operation_result); - g_free (realm); -+ g_free (preauth_source); - g_free (principal_for_display); - } - - static void - on_identity_added (GoaIdentityManager *identity_manager, - GoaIdentity *identity, - GoaIdentityService *self) - { - GoaObject *object; - const char *identifier; - - export_identity (self, identity); - - identifier = goa_identity_get_identifier (identity); - - object = find_object_with_principal (self, identifier, FALSE); - - if (object == NULL) - add_temporary_account (self, identity); - } - - static void - on_identity_removed (GoaIdentityManager *identity_manager, - GoaIdentity *identity, - GoaIdentityService *self) - { - GoaObject *object; - const char *identifier; - - identifier = goa_identity_get_identifier (identity); -@@ -1239,87 +1252,89 @@ on_identity_inquiry (GoaIdentityInquiry *inquiry, - request = system_prompt_open_request_new (self, inquiry, cancellable); - gcr_system_prompt_open_async (-1, - cancellable, - (GAsyncReadyCallback) - on_system_prompt_open, - request); - } - - static void - cancel_sign_in (GoaIdentityManager *identity_manager, - GoaIdentity *identity, - GSimpleAsyncResult *operation_result) - { - GoaIdentity *operation_identity; - - operation_identity = g_simple_async_result_get_source_tag (operation_result); - if (operation_identity == identity) - { - GCancellable *cancellable; - - cancellable = g_object_get_data (G_OBJECT (operation_result), - "cancellable"); - g_cancellable_cancel (cancellable); - } - } - - static void - sign_in (GoaIdentityService *self, - const char *identifier, - gconstpointer initial_password, -+ const char *preauth_source, - GoaIdentitySignInFlags flags, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) - { - GSimpleAsyncResult *operation_result; - - goa_debug ("GoaIdentityService: asking to sign in"); - - operation_result = g_simple_async_result_new (G_OBJECT (self), - callback, - user_data, - NULL); - g_simple_async_result_set_check_cancellable (operation_result, cancellable); - - g_object_set_data (G_OBJECT (operation_result), - "cancellable", - cancellable); - g_signal_connect_object (G_OBJECT (self->priv->identity_manager), - "identity-refreshed", - G_CALLBACK (cancel_sign_in), - operation_result, - 0); - - goa_identity_manager_sign_identity_in (self->priv->identity_manager, - identifier, - initial_password, -+ preauth_source, - flags, - (GoaIdentityInquiryFunc) - on_identity_inquiry, - self, - cancellable, - (GAsyncReadyCallback) - on_identity_signed_in, - operation_result); - } - - static void - on_identity_expiring (GoaIdentityManager *identity_manager, - GoaIdentity *identity, - GoaIdentityService *self) - { - const char *principal; - GoaObject *object; - - principal = goa_identity_get_identifier (identity); - - goa_debug ("GoaIdentityService: identity %s expiring", principal); - - object = find_object_with_principal (self, principal, TRUE); - - if (object == NULL) - return; - - ensure_account_credentials (self, object); - } - -diff --git a/src/goaidentity/goakerberosidentity.c b/src/goaidentity/goakerberosidentity.c -index c3a65f6..7641102 100644 ---- a/src/goaidentity/goakerberosidentity.c -+++ b/src/goaidentity/goakerberosidentity.c -@@ -25,60 +25,62 @@ - #include "goaidentity.h" - #include "goakerberosidentity.h" - #include "goakerberosidentityinquiry.h" - #include "goaalarm.h" - #include "goalogging.h" - - #include - #include - #include - - #include - #include - #include - - typedef enum - { - VERIFICATION_LEVEL_UNVERIFIED, - VERIFICATION_LEVEL_ERROR, - VERIFICATION_LEVEL_EXISTS, - VERIFICATION_LEVEL_SIGNED_IN - } VerificationLevel; - - struct _GoaKerberosIdentityPrivate - { - krb5_context kerberos_context; - krb5_ccache credentials_cache; - - char *identifier; - guint identifier_idle_id; - -+ char *preauth_identity_source; -+ - krb5_timestamp expiration_time; - guint expiration_time_idle_id; - - GoaAlarm *expiration_alarm; - GoaAlarm *expiring_alarm; - GoaAlarm *renewal_alarm; - - VerificationLevel cached_verification_level; - guint is_signed_in_idle_id; - }; - - enum - { - EXPIRING, - EXPIRED, - UNEXPIRED, - NEEDS_RENEWAL, - NEEDS_REFRESH, - NUMBER_OF_SIGNALS, - }; - - enum - { - PROP_0, - PROP_IDENTIFIER, - PROP_IS_SIGNED_IN, - PROP_EXPIRATION_TIMESTAMP - }; - - static guint signals[NUMBER_OF_SIGNALS] = { 0 }; -@@ -86,60 +88,62 @@ static guint signals[NUMBER_OF_SIGNALS] = { 0 }; - static void identity_interface_init (GoaIdentityInterface *interface); - static void initable_interface_init (GInitableIface *interface); - static void reset_alarms (GoaKerberosIdentity *self); - static void clear_alarms (GoaKerberosIdentity *self); - static gboolean goa_kerberos_identity_is_signed_in (GoaIdentity *identity); - static void set_error_from_krb5_error_code (GoaKerberosIdentity *self, - GError **error, - gint code, - krb5_error_code error_code, - const char *format, - ...); - - G_LOCK_DEFINE_STATIC (identity_lock); - - G_DEFINE_TYPE_WITH_CODE (GoaKerberosIdentity, - goa_kerberos_identity, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, - initable_interface_init) - G_IMPLEMENT_INTERFACE (GOA_TYPE_IDENTITY, - identity_interface_init)); - static void - goa_kerberos_identity_dispose (GObject *object) - { - GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (object); - - G_LOCK (identity_lock); - g_clear_object (&self->priv->renewal_alarm); - g_clear_object (&self->priv->expiring_alarm); - g_clear_object (&self->priv->expiration_alarm); -+ g_clear_pointer (&self->priv->preauth_identity_source, -+ g_free); - G_UNLOCK (identity_lock); - - G_OBJECT_CLASS (goa_kerberos_identity_parent_class)->dispose (object); - - } - - static void - goa_kerberos_identity_finalize (GObject *object) - { - GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (object); - - g_free (self->priv->identifier); - - if (self->priv->credentials_cache != NULL) - krb5_cc_close (self->priv->kerberos_context, self->priv->credentials_cache); - - G_OBJECT_CLASS (goa_kerberos_identity_parent_class)->finalize (object); - } - - static void - goa_kerberos_identity_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *param_spec) - { - GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (object); - - switch (property_id) - { - case PROP_IDENTIFIER: -@@ -385,108 +389,152 @@ goa_kerberos_identity_get_realm_name (GoaKerberosIdentity *self) - krb5_principal principal; - krb5_error_code error_code; - krb5_data *realm; - char *realm_name; - - if (self->priv->identifier == NULL) - return NULL; - - error_code = krb5_parse_name (self->priv->kerberos_context, - self->priv->identifier, &principal); - - if (error_code != 0) - { - const char *error_message; - error_message = - krb5_get_error_message (self->priv->kerberos_context, error_code); - goa_debug - ("GoaKerberosIdentity: Error parsing identity %s into kerberos principal: %s", - self->priv->identifier, error_message); - krb5_free_error_message (self->priv->kerberos_context, error_message); - return NULL; - } - - realm = krb5_princ_realm (self->priv->kerberos_context, principal); - realm_name = g_strndup (realm->data, realm->length); - krb5_free_principal (self->priv->kerberos_context, principal); - - return realm_name; - } - -+char * -+goa_kerberos_identity_get_preauthentication_source (GoaKerberosIdentity *self) -+{ -+ return g_strdup (self->priv->preauth_identity_source); -+} -+ - static const char * - goa_kerberos_identity_get_identifier (GoaIdentity *identity) - { - GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (identity); - - return self->priv->identifier; - } - - static gboolean - credentials_validate_existence (GoaKerberosIdentity *self, - krb5_principal principal, krb5_creds * credentials) - { - /* Checks if default principal associated with the cache has a valid - * ticket granting ticket in the passed in credentials - */ - - if (krb5_is_config_principal (self->priv->kerberos_context, credentials->server)) - return FALSE; - - /* looking for the krbtgt / REALM pair, so it should be exactly 2 items */ - if (krb5_princ_size (self->priv->kerberos_context, credentials->server) != 2) - return FALSE; - - if (!krb5_realm_compare (self->priv->kerberos_context, - credentials->server, principal)) - { - /* credentials are from some other realm */ - return FALSE; - } - - if (strncmp (credentials->server->data[0].data, - KRB5_TGS_NAME, credentials->server->data[0].length) != 0) - { - /* credentials aren't for ticket granting */ - return FALSE; - } - - if (credentials->server->data[1].length != principal->realm.length || - memcmp (credentials->server->data[1].data, - principal->realm.data, principal->realm.length) != 0) - { - /* credentials are for some other realm */ - return FALSE; - } - - return TRUE; - } - -+static gboolean -+snoop_preauth_identity_from_credentials (GoaKerberosIdentity *self, -+ krb5_creds *credentials, -+ char **identity_source) -+{ -+ GRegex *regex; -+ GMatchInfo *match_info = NULL; -+ gboolean identity_source_exposed = FALSE; -+ -+ if (!krb5_is_config_principal (self->priv->kerberos_context, credentials->server)) -+ return FALSE; -+ -+ regex = g_regex_new ("\"X509_user_identity\":\"(?P[^\"]*)\"", -+ G_REGEX_MULTILINE | G_REGEX_CASELESS | G_REGEX_RAW, -+ 0, -+ NULL); -+ -+ if (regex == NULL) -+ return FALSE; -+ -+ g_regex_match_full (regex, credentials->ticket.data, credentials->ticket.length, 0, 0, &match_info, NULL); -+ -+ if (match_info != NULL && g_match_info_matches (match_info)) -+ { -+ if (identity_source) -+ { -+ g_free (*identity_source); -+ *identity_source = g_match_info_fetch_named (match_info, "identity_source"); -+ } -+ identity_source_exposed = TRUE; -+ } -+ -+ g_match_info_free (match_info); -+ g_regex_unref (regex); -+ -+ return identity_source_exposed; -+} -+ - static krb5_timestamp - get_current_time (GoaKerberosIdentity *self) - { - krb5_timestamp current_time; - krb5_error_code error_code; - - error_code = krb5_timeofday (self->priv->kerberos_context, ¤t_time); - - if (error_code != 0) - { - const char *error_message; - - error_message = - krb5_get_error_message (self->priv->kerberos_context, error_code); - goa_debug ("GoaKerberosIdentity: Error getting current time: %s", error_message); - krb5_free_error_message (self->priv->kerberos_context, error_message); - return 0; - } - - return current_time; - } - - typedef struct - { - GoaKerberosIdentity *self; - guint *idle_id; - const char *property_name; - } NotifyRequest; - - static void -@@ -537,60 +585,61 @@ set_expiration_time (GoaKerberosIdentity *self, - if (self->priv->expiration_time != expiration_time) - { - self->priv->expiration_time = expiration_time; - queue_notify (self, - &self->priv->expiration_time_idle_id, - "expiration-timestamp"); - } - } - - static gboolean - credentials_are_expired (GoaKerberosIdentity *self, - krb5_creds *credentials) - { - krb5_timestamp current_time; - - current_time = get_current_time (self); - - set_expiration_time (self, MAX (credentials->times.endtime, - self->priv->expiration_time)); - - if (credentials->times.endtime <= current_time) - { - return TRUE; - } - - return FALSE; - } - - static VerificationLevel - verify_identity (GoaKerberosIdentity *self, -+ char **preauth_identity_source, - GError **error) - { - krb5_principal principal; - krb5_cc_cursor cursor; - krb5_creds credentials; - krb5_error_code error_code; - VerificationLevel verification_level; - - set_expiration_time (self, 0); - - if (self->priv->credentials_cache == NULL) - return VERIFICATION_LEVEL_UNVERIFIED; - - error_code = krb5_cc_get_principal (self->priv->kerberos_context, - self->priv->credentials_cache, - &principal); - - if (error_code != 0) - { - if (error_code == KRB5_CC_END || error_code == KRB5_FCC_NOFILE) - return VERIFICATION_LEVEL_UNVERIFIED; - - set_error_from_krb5_error_code (self, - error, - GOA_IDENTITY_ERROR_NOT_FOUND, - error_code, - _("Could not find identity in " - "credential cache: %k")); - return VERIFICATION_LEVEL_ERROR; - } -@@ -599,60 +648,64 @@ verify_identity (GoaKerberosIdentity *self, - self->priv->credentials_cache, &cursor); - if (error_code != 0) - { - set_error_from_krb5_error_code (self, - error, - GOA_IDENTITY_ERROR_CREDENTIALS_UNAVAILABLE, - error_code, - _("Could not find identity " - "credentials in cache: %k")); - - verification_level = VERIFICATION_LEVEL_ERROR; - goto out; - } - - verification_level = VERIFICATION_LEVEL_UNVERIFIED; - - error_code = krb5_cc_next_cred (self->priv->kerberos_context, - self->priv->credentials_cache, - &cursor, - &credentials); - - while (error_code == 0) - { - if (credentials_validate_existence (self, principal, &credentials)) - { - if (!credentials_are_expired (self, &credentials)) - verification_level = VERIFICATION_LEVEL_SIGNED_IN; - else - verification_level = VERIFICATION_LEVEL_EXISTS; - } -+ else -+ { -+ snoop_preauth_identity_from_credentials (self, &credentials, preauth_identity_source); -+ } - - krb5_free_cred_contents (self->priv->kerberos_context, &credentials); - - error_code = krb5_cc_next_cred (self->priv->kerberos_context, - self->priv->credentials_cache, - &cursor, - &credentials); - } - - if (error_code != KRB5_CC_END) - { - verification_level = VERIFICATION_LEVEL_ERROR; - - set_error_from_krb5_error_code (self, - error, - GOA_IDENTITY_ERROR_ENUMERATING_CREDENTIALS, - error_code, - _("Could not sift through identity " - "credentials in cache: %k")); - goto end_sequence; - } - - end_sequence: - error_code = krb5_cc_end_seq_get (self->priv->kerberos_context, - self->priv->credentials_cache, - &cursor); - - if (error_code != 0) - { - verification_level = VERIFICATION_LEVEL_ERROR; -@@ -900,61 +953,61 @@ reset_alarms (GoaKerberosIdentity *self) - static void - clear_alarms (GoaKerberosIdentity *self) - { - disconnect_alarm_signals (self); - clear_alarm_and_unref_on_idle (self, &self->priv->renewal_alarm); - clear_alarm_and_unref_on_idle (self, &self->priv->expiring_alarm); - clear_alarm_and_unref_on_idle (self, &self->priv->expiration_alarm); - } - - static gboolean - goa_kerberos_identity_initable_init (GInitable *initable, - GCancellable *cancellable, - GError **error) - { - GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (initable); - GError *verification_error; - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - return FALSE; - - if (self->priv->identifier == NULL) - { - self->priv->identifier = get_identifier (self, error); - - if (self->priv->identifier != NULL) - queue_notify (self, &self->priv->identifier_idle_id, "identifier"); - } - - verification_error = NULL; - self->priv->cached_verification_level = -- verify_identity (self, &verification_error); -+ verify_identity (self, &self->priv->preauth_identity_source, &verification_error); - - switch (self->priv->cached_verification_level) - { - case VERIFICATION_LEVEL_EXISTS: - case VERIFICATION_LEVEL_SIGNED_IN: - reset_alarms (self); - - queue_notify (self, &self->priv->is_signed_in_idle_id, "is-signed-in"); - return TRUE; - - case VERIFICATION_LEVEL_UNVERIFIED: - return TRUE; - - case VERIFICATION_LEVEL_ERROR: - if (verification_error != NULL) - { - g_propagate_error (error, verification_error); - return FALSE; - } - default: - g_set_error (error, - GOA_IDENTITY_ERROR, - GOA_IDENTITY_ERROR_VERIFYING, - _("No associated identification found")); - return FALSE; - - } - } - - static void -@@ -1105,60 +1158,61 @@ sign_in_operation_new (GoaKerberosIdentity *identity, - { - SignInOperation *operation; - - operation = g_slice_new0 (SignInOperation); - operation->identity = g_object_ref (identity); - operation->inquiry_func = inquiry_func; - operation->inquiry_data = inquiry_data; - operation->destroy_notify = destroy_notify; - - if (cancellable == NULL) - operation->cancellable = g_cancellable_new (); - else - operation->cancellable = g_object_ref (cancellable); - - return operation; - } - - static void - sign_in_operation_free (SignInOperation *operation) - { - g_object_unref (operation->identity); - g_object_unref (operation->cancellable); - - g_slice_free (SignInOperation, operation); - } - - gboolean - goa_kerberos_identity_sign_in (GoaKerberosIdentity *self, - const char *principal_name, - gconstpointer initial_password, -+ const char *preauth_source, - GoaIdentitySignInFlags flags, - GoaIdentityInquiryFunc inquiry_func, - gpointer inquiry_data, - GDestroyNotify destroy_notify, - GCancellable *cancellable, - GError **error) - { - SignInOperation *operation; - krb5_principal principal; - krb5_error_code error_code; - krb5_creds new_credentials; - krb5_get_init_creds_opt *options; - krb5_deltat start_time; - char *service_name; - gboolean signed_in; - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - return FALSE; - - error_code = krb5_get_init_creds_opt_alloc (self->priv->kerberos_context, - &options); - if (error_code != 0) - { - set_error_from_krb5_error_code (self, - error, - GOA_IDENTITY_ERROR_ALLOCATING_CREDENTIALS, - error_code, "%k"); - if (destroy_notify) - destroy_notify (inquiry_data); - return FALSE; -@@ -1176,60 +1230,67 @@ goa_kerberos_identity_sign_in (GoaKerberosIdentity *self, - { - g_free (self->priv->identifier); - self->priv->identifier = g_strdup (principal_name); - } - - error_code = krb5_parse_name (self->priv->kerberos_context, - principal_name, - &principal); - - if (error_code != 0) - { - set_error_from_krb5_error_code (self, - error, - GOA_IDENTITY_ERROR_PARSING_IDENTIFIER, - error_code, - "%k"); - if (destroy_notify) - destroy_notify (inquiry_data); - return FALSE; - } - - if ((flags & GOA_IDENTITY_SIGN_IN_FLAGS_DISALLOW_FORWARDING) == 0) - krb5_get_init_creds_opt_set_forwardable (options, TRUE); - - if ((flags & GOA_IDENTITY_SIGN_IN_FLAGS_DISALLOW_PROXYING) == 0) - krb5_get_init_creds_opt_set_proxiable (options, TRUE); - - if ((flags & GOA_IDENTITY_SIGN_IN_FLAGS_DISALLOW_RENEWAL) == 0) - krb5_get_init_creds_opt_set_renew_life (options, G_MAXINT); - -+ if (preauth_source != NULL) -+ { -+ krb5_get_init_creds_opt_set_pa (self->priv->kerberos_context, -+ options, -+ "X509_user_identity", preauth_source); -+ } -+ - /* Poke glibc in case the network changed - */ - res_init (); - - start_time = 0; - service_name = NULL; - error_code = krb5_get_init_creds_password (self->priv->kerberos_context, - &new_credentials, - principal, - (char *) - initial_password, - (krb5_prompter_fct) - on_kerberos_inquiry, - operation, - start_time, - service_name, - options); - - if (error_code == KRB5_LIBOS_PWDINTR) - g_cancellable_cancel (operation->cancellable); - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - { - if (destroy_notify) - destroy_notify (inquiry_data); - sign_in_operation_free (operation); - - krb5_free_principal (self->priv->kerberos_context, principal); - goto done; - } -@@ -1266,79 +1327,85 @@ goa_kerberos_identity_sign_in (GoaKerberosIdentity *self, - goa_debug ("GoaKerberosIdentity: identity signed in"); - signed_in = TRUE; - done: - - return signed_in; - } - - static void - update_identifier (GoaKerberosIdentity *self, GoaKerberosIdentity *new_identity) - { - char *new_identifier; - - new_identifier = get_identifier (self, NULL); - if (g_strcmp0 (self->priv->identifier, new_identifier) != 0) - { - g_free (self->priv->identifier); - self->priv->identifier = new_identifier; - queue_notify (self, &self->priv->identifier_idle_id, "identifier"); - } - else - { - g_free (new_identifier); - } - } - - void - goa_kerberos_identity_update (GoaKerberosIdentity *self, - GoaKerberosIdentity *new_identity) - { - VerificationLevel verification_level; -+ char *preauth_identity_source = NULL; - - if (self->priv->credentials_cache != NULL) - krb5_cc_close (self->priv->kerberos_context, self->priv->credentials_cache); - - krb5_cc_dup (new_identity->priv->kerberos_context, - new_identity->priv->credentials_cache, - &self->priv->credentials_cache); - - G_LOCK (identity_lock); - update_identifier (self, new_identity); - G_UNLOCK (identity_lock); - -- verification_level = verify_identity (self, NULL); -+ verification_level = verify_identity (self, &preauth_identity_source, NULL); - - if (verification_level == VERIFICATION_LEVEL_SIGNED_IN) - reset_alarms (self); - else - clear_alarms (self); - -+ G_LOCK (identity_lock); -+ g_free (self->priv->preauth_identity_source); -+ self->priv->preauth_identity_source = preauth_identity_source; -+ G_UNLOCK (identity_lock); -+ - if (verification_level != self->priv->cached_verification_level) - { - if (self->priv->cached_verification_level == VERIFICATION_LEVEL_SIGNED_IN && - verification_level == VERIFICATION_LEVEL_EXISTS) - { - - G_LOCK (identity_lock); - self->priv->cached_verification_level = verification_level; - G_UNLOCK (identity_lock); - - g_signal_emit (G_OBJECT (self), signals[EXPIRED], 0); - } - else if (self->priv->cached_verification_level == VERIFICATION_LEVEL_EXISTS && - verification_level == VERIFICATION_LEVEL_SIGNED_IN) - { - - G_LOCK (identity_lock); - self->priv->cached_verification_level = verification_level; - G_UNLOCK (identity_lock); - - g_signal_emit (G_OBJECT (self), signals[UNEXPIRED], 0); - } - else - { - G_LOCK (identity_lock); - self->priv->cached_verification_level = verification_level; - G_UNLOCK (identity_lock); - } - queue_notify (self, &self->priv->is_signed_in_idle_id, "is-signed-in"); - } -diff --git a/src/goaidentity/goakerberosidentity.h b/src/goaidentity/goakerberosidentity.h -index 6e82835..e163016 100644 ---- a/src/goaidentity/goakerberosidentity.h -+++ b/src/goaidentity/goakerberosidentity.h -@@ -43,47 +43,49 @@ typedef enum _GoaKerberosIdentityDescriptionLevel - GoaKerberosIdentityDescriptionLevel; - - enum _GoaKerberosIdentityDescriptionLevel - { - GOA_KERBEROS_IDENTITY_DESCRIPTION_REALM, - GOA_KERBEROS_IDENTITY_DESCRIPTION_USERNAME_AND_REALM, - GOA_KERBEROS_IDENTITY_DESCRIPTION_USERNAME_ROLE_AND_REALM - }; - - struct _GoaKerberosIdentity - { - GObject parent; - - GoaKerberosIdentityPrivate *priv; - }; - - struct _GoaKerberosIdentityClass - { - GObjectClass parent_class; - }; - - GType goa_kerberos_identity_get_type (void); - - GoaIdentity *goa_kerberos_identity_new (krb5_context kerberos_context, - krb5_ccache cache, - GError **error); - - gboolean goa_kerberos_identity_sign_in (GoaKerberosIdentity *self, - const char *principal_name, - gconstpointer initial_password, -+ const char *preauth_source, - GoaIdentitySignInFlags flags, - GoaIdentityInquiryFunc inquiry_func, - gpointer inquiry_data, - GDestroyNotify destroy_notify, - GCancellable *cancellable, - GError **error); - void goa_kerberos_identity_update (GoaKerberosIdentity *identity, - GoaKerberosIdentity *new_identity); - gboolean goa_kerberos_identity_renew (GoaKerberosIdentity *self, - GError **error); - gboolean goa_kerberos_identity_erase (GoaKerberosIdentity *self, - GError **error); - - char *goa_kerberos_identity_get_principal_name (GoaKerberosIdentity *self); - char *goa_kerberos_identity_get_realm_name (GoaKerberosIdentity *self); -+char *goa_kerberos_identity_get_preauthentication_source (GoaKerberosIdentity *self); - G_END_DECLS - #endif /* __GOA_KERBEROS_IDENTITY_H__ */ -diff --git a/src/goaidentity/goakerberosidentitymanager.c b/src/goaidentity/goakerberosidentitymanager.c -index c4da420..1fa0807 100644 ---- a/src/goaidentity/goakerberosidentitymanager.c -+++ b/src/goaidentity/goakerberosidentitymanager.c -@@ -59,60 +59,61 @@ struct _GoaKerberosIdentityManagerPrivate - volatile int pending_refresh_count; - - guint polling_timeout_id; - }; - - typedef enum - { - OPERATION_TYPE_REFRESH, - OPERATION_TYPE_GET_IDENTITY, - OPERATION_TYPE_LIST, - OPERATION_TYPE_RENEW, - OPERATION_TYPE_SIGN_IN, - OPERATION_TYPE_SIGN_OUT, - OPERATION_TYPE_STOP_JOB - } OperationType; - - typedef struct - { - GCancellable *cancellable; - GoaKerberosIdentityManager *manager; - OperationType type; - GSimpleAsyncResult *result; - GIOSchedulerJob *job; - union - { - GoaIdentity *identity; - struct - { - const char *identifier; - gconstpointer initial_password; -+ char *preauth_source; - GoaIdentitySignInFlags sign_in_flags; - GoaIdentityInquiry *inquiry; - GoaIdentityInquiryFunc inquiry_func; - gpointer inquiry_data; - GMutex inquiry_lock; - GCond inquiry_finished_condition; - volatile gboolean is_inquiring; - }; - }; - } Operation; - - typedef struct - { - GoaKerberosIdentityManager *manager; - GoaIdentity *identity; - } IdentitySignalWork; - - static GoaIdentityManager *goa_kerberos_identity_manager_singleton; - - static void identity_manager_interface_init (GoaIdentityManagerInterface * - interface); - static void initable_interface_init (GInitableIface *interface); - - static void on_identity_expired (GoaIdentity *identity, - GoaKerberosIdentityManager *self); - - G_DEFINE_TYPE_WITH_CODE (GoaKerberosIdentityManager, - goa_kerberos_identity_manager, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GOA_TYPE_IDENTITY_MANAGER, -@@ -129,64 +130,68 @@ operation_new (GoaKerberosIdentityManager *self, - { - Operation *operation; - - operation = g_slice_new0 (Operation); - - operation->manager = self; - operation->type = type; - - if (cancellable == NULL) - cancellable = g_cancellable_new (); - else - g_object_ref (cancellable); - operation->cancellable = cancellable; - - if (result != NULL) - g_object_ref (result); - operation->result = result; - - operation->identity = NULL; - - return operation; - } - - static void - operation_free (Operation *operation) - { - g_clear_object (&operation->cancellable); - - if (operation->type != OPERATION_TYPE_SIGN_IN && - operation->type != OPERATION_TYPE_GET_IDENTITY) -- g_clear_object (&operation->identity); -+ { -+ g_clear_object (&operation->identity); -+ } - else -- g_clear_pointer (&operation->identifier, g_free); -- -+ { -+ g_clear_pointer (&operation->identifier, g_free); -+ g_clear_pointer (&operation->preauth_source, g_free); -+ } - g_clear_object (&operation->result); - - g_slice_free (Operation, operation); - } - - static void - schedule_refresh (GoaKerberosIdentityManager *self) - { - Operation *operation; - - g_atomic_int_inc (&self->priv->pending_refresh_count); - - operation = operation_new (self, NULL, OPERATION_TYPE_REFRESH, NULL); - g_async_queue_push (self->priv->pending_operations, operation); - } - - static IdentitySignalWork * - identity_signal_work_new (GoaKerberosIdentityManager *self, - GoaIdentity *identity) - { - IdentitySignalWork *work; - - work = g_slice_new (IdentitySignalWork); - work->manager = self; - work->identity = g_object_ref (identity); - - return work; - } - - static void -@@ -841,60 +846,61 @@ sign_in_identity (GoaKerberosIdentityManager *self, - _("Could not create credential cache for identity")); - g_simple_async_result_set_op_res_gpointer (operation->result, NULL, NULL); - return; - } - - identity = goa_kerberos_identity_new (self->priv->kerberos_context, - credentials_cache, - &error); - krb5_cc_close (self->priv->kerberos_context, credentials_cache); - if (identity == NULL) - { - g_simple_async_result_take_error (operation->result, error); - g_simple_async_result_set_op_res_gpointer (operation->result, - NULL, - NULL); - return; - } - } - else - { - g_object_ref (identity); - } - - g_hash_table_replace (self->priv->identities, - g_strdup (operation->identifier), - g_object_ref (identity)); - - if (!goa_kerberos_identity_sign_in (GOA_KERBEROS_IDENTITY (identity), - operation->identifier, - operation->initial_password, -+ operation->preauth_source, - operation->sign_in_flags, - (GoaIdentityInquiryFunc) - on_kerberos_identity_inquiry, - operation, - NULL, - operation->cancellable, - &error)) - { - g_simple_async_result_set_from_error (operation->result, error); - g_simple_async_result_set_op_res_gpointer (operation->result, - NULL, - NULL); - - } - else - { - g_simple_async_result_set_op_res_gpointer (operation->result, - g_object_ref (identity), - (GDestroyNotify) - g_object_unref); - } - - g_object_unref (identity); - } - - static void - sign_out_identity (GoaKerberosIdentityManager *self, - Operation *operation) - { - GError *error; -@@ -1156,83 +1162,85 @@ goa_kerberos_identity_manager_renew_identity (GoaIdentityManager *manager, - GoaKerberosIdentityManager *self = GOA_KERBEROS_IDENTITY_MANAGER (manager); - GSimpleAsyncResult *result; - Operation *operation; - - result = g_simple_async_result_new (G_OBJECT (self), - callback, - user_data, - goa_kerberos_identity_manager_renew_identity); - operation = operation_new (self, cancellable, OPERATION_TYPE_RENEW, result); - g_object_unref (result); - - operation->identity = g_object_ref (identity); - - g_async_queue_push (self->priv->pending_operations, operation); - } - - static void - goa_kerberos_identity_manager_renew_identity_finish (GoaIdentityManager *self, - GAsyncResult *result, - GError **error) - { - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), - error)) - return; - } - - static void - goa_kerberos_identity_manager_sign_identity_in (GoaIdentityManager *manager, - const char *identifier, - gconstpointer initial_password, -+ const char *preauth_source, - GoaIdentitySignInFlags flags, - GoaIdentityInquiryFunc inquiry_func, - gpointer inquiry_data, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) - { - GoaKerberosIdentityManager *self = GOA_KERBEROS_IDENTITY_MANAGER (manager); - GSimpleAsyncResult *result; - Operation *operation; - - result = g_simple_async_result_new (G_OBJECT (self), - callback, - user_data, - goa_kerberos_identity_manager_sign_identity_in); - operation = operation_new (self, cancellable, OPERATION_TYPE_SIGN_IN, result); - g_object_unref (result); - - operation->identifier = g_strdup (identifier); - /* Not duped. Caller is responsible for ensuring it stays alive - * for duration of operation - */ - operation->initial_password = initial_password; -+ operation->preauth_source = g_strdup (preauth_source); - operation->sign_in_flags = flags; - operation->inquiry_func = inquiry_func; - operation->inquiry_data = inquiry_data; - g_mutex_init (&operation->inquiry_lock); - g_cond_init (&operation->inquiry_finished_condition); - operation->is_inquiring = FALSE; - - g_async_queue_push (self->priv->pending_operations, operation); - } - - static GoaIdentity * - goa_kerberos_identity_manager_sign_identity_in_finish (GoaIdentityManager *self, - GAsyncResult *result, - GError **error) - { - GoaIdentity *identity; - - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) - return NULL; - - identity = - g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)); - - return identity; - } - - static void - goa_kerberos_identity_manager_sign_identity_out (GoaIdentityManager *manager, - GoaIdentity *identity, - GCancellable *cancellable, --- -1.8.3.1 - diff --git a/SOURCES/ensure-credentials-startup-and-network-change.patch b/SOURCES/ensure-credentials-startup-and-network-change.patch new file mode 100644 index 0000000..27d6ad0 --- /dev/null +++ b/SOURCES/ensure-credentials-startup-and-network-change.patch @@ -0,0 +1,999 @@ +From b1d87d540c2229dc9954efe73feebcaf5aad41eb Mon Sep 17 00:00:00 2001 +From: Debarshi Ray +Date: Wed, 27 May 2015 15:15:09 +0200 +Subject: [PATCH 01/12] daemon: Style fixes + +Use the name 'self' to refer to the instance. +--- + src/daemon/goadaemon.c | 138 ++++++++++++++++++++++++------------------------- + 1 file changed, 69 insertions(+), 69 deletions(-) + +diff --git a/src/daemon/goadaemon.c b/src/daemon/goadaemon.c +index 89cbed8..55a576d 100644 +--- a/src/daemon/goadaemon.c ++++ b/src/daemon/goadaemon.c +@@ -1,6 +1,6 @@ + /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + /* +- * Copyright (C) 2011, 2012 Red Hat, Inc. ++ * Copyright (C) 2011, 2012, 2015 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 +@@ -71,39 +71,39 @@ static gboolean on_account_handle_ensure_credentials (GoaAccount *acc + GDBusMethodInvocation *invocation, + gpointer user_data); + +-static void goa_daemon_reload_configuration (GoaDaemon *daemon); ++static void goa_daemon_reload_configuration (GoaDaemon *self); + + G_DEFINE_TYPE (GoaDaemon, goa_daemon, G_TYPE_OBJECT); + + static void + goa_daemon_finalize (GObject *object) + { +- GoaDaemon *daemon = GOA_DAEMON (object); ++ GoaDaemon *self = GOA_DAEMON (object); + +- if (daemon->config_timeout_id != 0) ++ if (self->config_timeout_id != 0) + { +- g_source_remove (daemon->config_timeout_id); ++ g_source_remove (self->config_timeout_id); + } + +- if (daemon->system_conf_dir_monitor != NULL) ++ if (self->system_conf_dir_monitor != NULL) + { +- g_signal_handlers_disconnect_by_func (daemon->system_conf_dir_monitor, on_file_monitor_changed, daemon); +- g_object_unref (daemon->system_conf_dir_monitor); ++ g_signal_handlers_disconnect_by_func (self->system_conf_dir_monitor, on_file_monitor_changed, self); ++ g_object_unref (self->system_conf_dir_monitor); + } +- if (daemon->home_conf_dir_monitor != NULL) ++ if (self->home_conf_dir_monitor != NULL) + { +- g_signal_handlers_disconnect_by_func (daemon->home_conf_dir_monitor, on_file_monitor_changed, daemon); +- g_object_unref (daemon->home_conf_dir_monitor); ++ g_signal_handlers_disconnect_by_func (self->home_conf_dir_monitor, on_file_monitor_changed, self); ++ g_object_unref (self->home_conf_dir_monitor); + } +- if (daemon->home_conf_file_monitor != NULL) ++ if (self->home_conf_file_monitor != NULL) + { +- g_signal_handlers_disconnect_by_func (daemon->home_conf_file_monitor, on_file_monitor_changed, daemon); +- g_object_unref (daemon->home_conf_file_monitor); ++ g_signal_handlers_disconnect_by_func (self->home_conf_file_monitor, on_file_monitor_changed, self); ++ g_object_unref (self->home_conf_file_monitor); + } + +- g_object_unref (daemon->manager); +- g_object_unref (daemon->object_manager); +- g_object_unref (daemon->connection); ++ g_object_unref (self->manager); ++ g_object_unref (self->object_manager); ++ g_object_unref (self->connection); + + G_OBJECT_CLASS (goa_daemon_parent_class)->finalize (object); + } +@@ -138,11 +138,11 @@ create_monitor (const gchar *path, gboolean is_dir) + static gboolean + on_config_file_monitor_timeout (gpointer user_data) + { +- GoaDaemon *daemon = GOA_DAEMON (user_data); ++ GoaDaemon *self = GOA_DAEMON (user_data); + +- daemon->config_timeout_id = 0; ++ self->config_timeout_id = 0; + g_info ("Reloading configuration files\n"); +- goa_daemon_reload_configuration (daemon); ++ goa_daemon_reload_configuration (self); + + return FALSE; + } +@@ -154,17 +154,17 @@ on_file_monitor_changed (GFileMonitor *monitor, + GFileMonitorEvent event_type, + gpointer user_data) + { +- GoaDaemon *daemon = GOA_DAEMON (user_data); ++ GoaDaemon *self = GOA_DAEMON (user_data); + +- if (daemon->config_timeout_id == 0) ++ if (self->config_timeout_id == 0) + { +- daemon->config_timeout_id = g_timeout_add (200, on_config_file_monitor_timeout, daemon); ++ self->config_timeout_id = g_timeout_add (200, on_config_file_monitor_timeout, self); + } + } + + #ifdef GOA_KERBEROS_ENABLED + static void +-activate_identity_service (GoaDaemon *daemon) ++activate_identity_service (GoaDaemon *self) + { + GoaProvider *provider; + +@@ -183,7 +183,7 @@ activate_identity_service (GoaDaemon *daemon) + #endif + + static void +-goa_daemon_init (GoaDaemon *daemon) ++goa_daemon_init (GoaDaemon *self) + { + static volatile GQuark goa_error_domain = 0; + GoaObjectSkeleton *object; +@@ -196,20 +196,20 @@ goa_daemon_init (GoaDaemon *daemon) + goa_error_domain; /* shut up -Wunused-but-set-variable */ + + /* TODO: maybe nicer to pass in a GDBusConnection* construct property */ +- daemon->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); ++ self->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); + + /* Create object manager */ +- daemon->object_manager = g_dbus_object_manager_server_new ("/org/gnome/OnlineAccounts"); ++ self->object_manager = g_dbus_object_manager_server_new ("/org/gnome/OnlineAccounts"); + + /* Create and export Manager */ +- daemon->manager = goa_manager_skeleton_new (); +- g_signal_connect (daemon->manager, ++ self->manager = goa_manager_skeleton_new (); ++ g_signal_connect (self->manager, + "handle-add-account", + G_CALLBACK (on_manager_handle_add_account), +- daemon); ++ self); + object = goa_object_skeleton_new ("/org/gnome/OnlineAccounts/Manager"); +- goa_object_skeleton_set_manager (object, daemon->manager); +- g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object)); ++ goa_object_skeleton_set_manager (object, self->manager); ++ g_dbus_object_manager_server_export (self->object_manager, G_DBUS_OBJECT_SKELETON (object)); + g_object_unref (object); + + /* create ~/.config/goa-1.0 directory */ +@@ -222,19 +222,19 @@ goa_daemon_init (GoaDaemon *daemon) + + /* set up file monitoring */ + path = g_strdup_printf ("%s/goa-1.0/accounts.conf", g_get_user_config_dir ()); +- daemon->home_conf_file_monitor = create_monitor (path, FALSE); +- if (daemon->home_conf_file_monitor != NULL) +- g_signal_connect (daemon->home_conf_file_monitor, "changed", G_CALLBACK (on_file_monitor_changed), daemon); ++ self->home_conf_file_monitor = create_monitor (path, FALSE); ++ if (self->home_conf_file_monitor != NULL) ++ g_signal_connect (self->home_conf_file_monitor, "changed", G_CALLBACK (on_file_monitor_changed), self); + g_free (path); + + /* prime the list of accounts */ +- goa_daemon_reload_configuration (daemon); ++ goa_daemon_reload_configuration (self); + + /* Export objects */ +- g_dbus_object_manager_server_set_connection (daemon->object_manager, daemon->connection); ++ g_dbus_object_manager_server_set_connection (self->object_manager, self->connection); + + #ifdef GOA_KERBEROS_ENABLED +- activate_identity_service (daemon); ++ activate_identity_service (self); + #endif + } + +@@ -331,7 +331,7 @@ key_file_data_new (GKeyFile *key_file, + /* ---------------------------------------------------------------------------------------------------- */ + + static void +-add_config_file (GoaDaemon *daemon, ++add_config_file (GoaDaemon *self, + const gchar *path, + GHashTable *group_name_to_key_file_data, + GList **key_files_to_free) +@@ -363,7 +363,7 @@ add_config_file (GoaDaemon *daemon, + gsize num_groups; + guint n; + +- guid = g_dbus_connection_get_guid (daemon->connection); ++ guid = g_dbus_connection_get_guid (self->connection); + groups = g_key_file_get_groups (key_file, &num_groups); + for (n = 0; n < num_groups; n++) + { +@@ -421,7 +421,7 @@ add_config_file (GoaDaemon *daemon, + + /* returns FALSE if object is not (or no longer) valid */ + static gboolean +-update_account_object (GoaDaemon *daemon, ++update_account_object (GoaDaemon *self, + GoaObjectSkeleton *object, + const gchar *path, + const gchar *group, +@@ -439,7 +439,7 @@ update_account_object (GoaDaemon *daemon, + gchar *serialized_icon; + GError *error; + +- g_return_val_if_fail (GOA_IS_DAEMON (daemon), FALSE); ++ g_return_val_if_fail (GOA_IS_DAEMON (self), FALSE); + g_return_val_if_fail (G_IS_DBUS_OBJECT_SKELETON (object), FALSE); + g_return_val_if_fail (group != NULL, FALSE); + g_return_val_if_fail (key_file != NULL, FALSE); +@@ -480,7 +480,7 @@ update_account_object (GoaDaemon *daemon, + goa_account_set_presentation_identity (account, presentation_identity); + + error = NULL; +- if (!goa_provider_build_object (provider, object, key_file, group, daemon->connection, just_added, &error)) ++ if (!goa_provider_build_object (provider, object, key_file, group, self->connection, just_added, &error)) + { + g_warning ("Error parsing account: %s (%s, %d)", + error->message, g_quark_to_string (error->domain), error->code); +@@ -519,7 +519,7 @@ object_path_to_group (const gchar *object_path) + } + + static void +-process_config_entries (GoaDaemon *daemon, ++process_config_entries (GoaDaemon *self, + GHashTable *group_name_to_key_file_data) + { + GHashTableIter iter; +@@ -535,7 +535,7 @@ process_config_entries (GoaDaemon *daemon, + existing_object_paths = NULL; + { + GList *existing_objects; +- existing_objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (daemon->object_manager)); ++ existing_objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (self->object_manager)); + for (l = existing_objects; l != NULL; l = l->next) + { + GoaObject *object = GOA_OBJECT (l->data); +@@ -579,13 +579,13 @@ process_config_entries (GoaDaemon *daemon, + { + const gchar *object_path = l->data; + GoaObject *object; +- object = GOA_OBJECT (g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (daemon->object_manager), object_path)); ++ object = GOA_OBJECT (g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (self->object_manager), object_path)); + g_warn_if_fail (object != NULL); + g_signal_handlers_disconnect_by_func (goa_object_peek_account (object), + G_CALLBACK (on_account_handle_remove), + daemon); + g_debug ("removing %s", object_path); +- g_warn_if_fail (g_dbus_object_manager_server_unexport (daemon->object_manager, object_path)); ++ g_warn_if_fail (g_dbus_object_manager_server_unexport (self->object_manager, object_path)); + } + for (l = added; l != NULL; l = l->next) + { +@@ -600,22 +600,22 @@ process_config_entries (GoaDaemon *daemon, + g_warn_if_fail (key_file_data != NULL); + + object = goa_object_skeleton_new (object_path); +- if (update_account_object (daemon, ++ if (update_account_object (self, + object, + key_file_data->path, + group, + key_file_data->key_file, + TRUE)) + { +- g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object)); ++ g_dbus_object_manager_server_export (self->object_manager, G_DBUS_OBJECT_SKELETON (object)); + g_signal_connect (goa_object_peek_account (GOA_OBJECT (object)), + "handle-remove", + G_CALLBACK (on_account_handle_remove), +- daemon); ++ self); + g_signal_connect (goa_object_peek_account (GOA_OBJECT (object)), + "handle-ensure-credentials", + G_CALLBACK (on_account_handle_ensure_credentials), +- daemon); ++ self); + } + g_object_unref (object); + g_free (group); +@@ -632,9 +632,9 @@ process_config_entries (GoaDaemon *daemon, + key_file_data = g_hash_table_lookup (group_name_to_key_file_data, group); + g_warn_if_fail (key_file_data != NULL); + +- object = GOA_OBJECT (g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (daemon->object_manager), object_path)); ++ object = GOA_OBJECT (g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (self->object_manager), object_path)); + g_warn_if_fail (object != NULL); +- if (!update_account_object (daemon, ++ if (!update_account_object (self, + GOA_OBJECT_SKELETON (object), + key_file_data->path, + group, +@@ -643,11 +643,11 @@ process_config_entries (GoaDaemon *daemon, + { + g_signal_handlers_disconnect_by_func (goa_object_peek_account (object), + G_CALLBACK (on_account_handle_remove), +- daemon); ++ self); + g_signal_handlers_disconnect_by_func (goa_object_peek_account (object), + G_CALLBACK (on_account_handle_ensure_credentials), +- daemon); +- g_warn_if_fail (g_dbus_object_manager_server_unexport (daemon->object_manager, object_path)); ++ self); ++ g_warn_if_fail (g_dbus_object_manager_server_unexport (self->object_manager, object_path)); + } + g_object_unref (object); + g_free (group); +@@ -664,14 +664,14 @@ process_config_entries (GoaDaemon *daemon, + + /* + * goa_daemon_reload_configuration: +- * @daemon: A #GoaDaemon ++ * @self: A #GoaDaemon + * + * Updates the accounts_objects member from stored configuration - + * typically called at startup or when a change on the configuration + * files has been detected. + */ + static void +-goa_daemon_reload_configuration (GoaDaemon *daemon) ++goa_daemon_reload_configuration (GoaDaemon *self) + { + GList *key_files_to_free; + GHashTable *group_name_to_key_file_data; +@@ -685,11 +685,11 @@ goa_daemon_reload_configuration (GoaDaemon *daemon) + + /* Read the main user config file at $HOME/.config/goa-1.0/accounts.conf */ + path = g_strdup_printf ("%s/goa-1.0/accounts.conf", g_get_user_config_dir ()); +- add_config_file (daemon, path, group_name_to_key_file_data, &key_files_to_free); ++ add_config_file (self, path, group_name_to_key_file_data, &key_files_to_free); + g_free (path); + + /* now process the group_name_to_key_file_data hash table */ +- process_config_entries (daemon, group_name_to_key_file_data); ++ process_config_entries (self, group_name_to_key_file_data); + + g_hash_table_unref (group_name_to_key_file_data); + g_list_foreach (key_files_to_free, (GFunc) g_key_file_free, NULL); +@@ -697,7 +697,7 @@ goa_daemon_reload_configuration (GoaDaemon *daemon) + } + + static gchar * +-generate_new_id (GoaDaemon *daemon) ++generate_new_id (GoaDaemon *self) + { + static guint counter = 0; + GDateTime *dt; +@@ -915,11 +915,11 @@ on_manager_handle_add_account (GoaManager *manager, + GVariant *details, + gpointer user_data) + { +- GoaDaemon *daemon = GOA_DAEMON (user_data); ++ GoaDaemon *self = GOA_DAEMON (user_data); + AddAccountData *data; + + data = g_slice_new0 (AddAccountData); +- data->daemon = g_object_ref (daemon); ++ data->daemon = g_object_ref (self); + data->manager = g_object_ref (manager); + data->invocation = g_object_ref (invocation); + data->provider_type = g_strdup (provider_type); +@@ -940,7 +940,7 @@ on_account_handle_remove (GoaAccount *account, + GDBusMethodInvocation *invocation, + gpointer user_data) + { +- GoaDaemon *daemon = GOA_DAEMON (user_data); ++ GoaDaemon *self = GOA_DAEMON (user_data); + GoaProvider *provider; + GKeyFile *key_file; + const gchar *provider_type; +@@ -1037,7 +1037,7 @@ on_account_handle_remove (GoaAccount *account, + goto out; + } + +- goa_daemon_reload_configuration (daemon); ++ goa_daemon_reload_configuration (self); + + goa_account_complete_remove (account, invocation); + +@@ -1062,13 +1062,13 @@ typedef struct + } EnsureData; + + static EnsureData * +-ensure_data_new (GoaDaemon *daemon, ++ensure_data_new (GoaDaemon *self, + GoaObject *object, + GDBusMethodInvocation *invocation) + { + EnsureData *data; + data = g_slice_new0 (EnsureData); +- data->daemon = g_object_ref (daemon); ++ data->daemon = g_object_ref (self); + data->object = g_object_ref (object); + data->invocation = invocation; + return data; +@@ -1156,7 +1156,7 @@ on_account_handle_ensure_credentials (GoaAccount *account, + GDBusMethodInvocation *invocation, + gpointer user_data) + { +- GoaDaemon *daemon = GOA_DAEMON (user_data); ++ GoaDaemon *self = GOA_DAEMON (user_data); + GoaProvider *provider = NULL; + GoaObject *object; + +@@ -1177,7 +1177,7 @@ on_account_handle_ensure_credentials (GoaAccount *account, + object, + NULL, /* GCancellable */ + (GAsyncReadyCallback) ensure_credentials_cb, +- ensure_data_new (daemon, object, invocation)); ++ ensure_data_new (self, object, invocation)); + + out: + g_clear_object (&provider); +-- +2.1.0 + + +From dec43aa3281420cc8bbb51e70b0db27886d0080a Mon Sep 17 00:00:00 2001 +From: Debarshi Ray +Date: Wed, 27 May 2015 17:17:42 +0200 +Subject: [PATCH 02/12] daemon: Use G_SOURCE_REMOVE instead of FALSE + +--- + src/daemon/goadaemon.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/daemon/goadaemon.c b/src/daemon/goadaemon.c +index 55a576d..a7b2967 100644 +--- a/src/daemon/goadaemon.c ++++ b/src/daemon/goadaemon.c +@@ -144,7 +144,7 @@ on_config_file_monitor_timeout (gpointer user_data) + g_info ("Reloading configuration files\n"); + goa_daemon_reload_configuration (self); + +- return FALSE; ++ return G_SOURCE_REMOVE; + } + + static void +-- +2.1.0 + + +From 1e6a783a779efab7524b981c0c164bfa393577ae Mon Sep 17 00:00:00 2001 +From: Debarshi Ray +Date: Wed, 27 May 2015 19:07:39 +0200 +Subject: [PATCH 03/12] daemon: Use g_clear_object wherever applicable + +https://bugzilla.gnome.org/show_bug.cgi?id=693578 +--- + src/daemon/goadaemon.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/src/daemon/goadaemon.c b/src/daemon/goadaemon.c +index a7b2967..e6a559d 100644 +--- a/src/daemon/goadaemon.c ++++ b/src/daemon/goadaemon.c +@@ -445,6 +445,8 @@ update_account_object (GoaDaemon *self, + g_return_val_if_fail (key_file != NULL, FALSE); + + ret = FALSE; ++ account = NULL; ++ provider = NULL; + identity = NULL; + type = NULL; + account = NULL; +@@ -499,12 +501,10 @@ update_account_object (GoaDaemon *self, + + out: + g_free (serialized_icon); +- if (icon != NULL) +- g_object_unref (icon); ++ g_clear_object (&icon); + g_free (name); +- if (provider != NULL) +- g_object_unref (provider); +- g_object_unref (account); ++ g_clear_object (&provider); ++ g_clear_object (&account); + g_free (type); + g_free (identity); + g_free (presentation_identity); +@@ -1042,8 +1042,7 @@ on_account_handle_remove (GoaAccount *account, + goa_account_complete_remove (account, invocation); + + out: +- if (provider != NULL) +- g_object_unref (provider); ++ g_clear_object (&provider); + g_free (data); + if (key_file != NULL) + g_key_file_free (key_file); +-- +2.1.0 + + +From 6f91a7a8c3106d4c3e7c11e819e07316cd3aa4c8 Mon Sep 17 00:00:00 2001 +From: Debarshi Ray +Date: Wed, 27 May 2015 19:11:54 +0200 +Subject: [PATCH 04/12] daemon: Use g_list_free_full wherever applicable + +https://bugzilla.gnome.org/show_bug.cgi?id=693578 +--- + src/daemon/goadaemon.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +diff --git a/src/daemon/goadaemon.c b/src/daemon/goadaemon.c +index e6a559d..79d6f26 100644 +--- a/src/daemon/goadaemon.c ++++ b/src/daemon/goadaemon.c +@@ -544,8 +544,7 @@ process_config_entries (GoaDaemon *self, + if (g_str_has_prefix (object_path, "/org/gnome/OnlineAccounts/Accounts/")) + existing_object_paths = g_list_prepend (existing_object_paths, g_strdup (object_path)); + } +- g_list_foreach (existing_objects, (GFunc) g_object_unref, NULL); +- g_list_free (existing_objects); ++ g_list_free_full (existing_objects, g_object_unref); + } + + config_object_paths = NULL; +@@ -656,10 +655,8 @@ process_config_entries (GoaDaemon *self, + g_list_free (removed); + g_list_free (added); + g_list_free (unchanged); +- g_list_foreach (existing_object_paths, (GFunc) g_free, NULL); +- g_list_free (existing_object_paths); +- g_list_foreach (config_object_paths, (GFunc) g_free, NULL); +- g_list_free (config_object_paths); ++ g_list_free_full (existing_object_paths, g_free); ++ g_list_free_full (config_object_paths, g_free); + } + + /* +@@ -692,8 +689,7 @@ goa_daemon_reload_configuration (GoaDaemon *self) + process_config_entries (self, group_name_to_key_file_data); + + g_hash_table_unref (group_name_to_key_file_data); +- g_list_foreach (key_files_to_free, (GFunc) g_key_file_free, NULL); +- g_list_free (key_files_to_free); ++ g_list_free_full (key_files_to_free, (GDestroyNotify) g_key_file_free); + } + + static gchar * +-- +2.1.0 + + +From df7b534a62e49be6b32360e01ea19f542b5ea548 Mon Sep 17 00:00:00 2001 +From: Debarshi Ray +Date: Wed, 27 May 2015 19:13:18 +0200 +Subject: [PATCH 05/12] daemon: Remove redundant NULL check + +https://bugzilla.gnome.org/show_bug.cgi?id=693578 +--- + src/daemon/goadaemon.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/daemon/goadaemon.c b/src/daemon/goadaemon.c +index 79d6f26..eeb49e6 100644 +--- a/src/daemon/goadaemon.c ++++ b/src/daemon/goadaemon.c +@@ -881,8 +881,7 @@ get_all_providers_cb (GObject *source, + + out: + g_free (object_path); +- if (providers != NULL) +- g_list_free_full (providers, g_object_unref); ++ g_list_free_full (providers, g_object_unref); + g_free (key_file_data); + g_free (group); + g_free (id); +-- +2.1.0 + + +From e1568184f6e6a18b0a10ff94f18729fd29892edb Mon Sep 17 00:00:00 2001 +From: Debarshi Ray +Date: Thu, 28 May 2015 13:26:06 +0200 +Subject: [PATCH 06/12] daemon: Remove redundant function call + +https://bugzilla.gnome.org/show_bug.cgi?id=693578 +--- + src/daemon/goadaemon.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/src/daemon/goadaemon.c b/src/daemon/goadaemon.c +index eeb49e6..f933e69 100644 +--- a/src/daemon/goadaemon.c ++++ b/src/daemon/goadaemon.c +@@ -1138,9 +1138,7 @@ ensure_credentials_cb (GoaProvider *provider, + g_message ("%s: Setting AttentionNeeded to FALSE because EnsureCredentials() succeded\n", + g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object))); + } +- goa_account_complete_ensure_credentials (goa_object_peek_account (data->object), +- data->invocation, +- expires_in); ++ goa_account_complete_ensure_credentials (account, data->invocation, expires_in); + } + ensure_data_unref (data); + } +-- +2.1.0 + + +From b8d56056ecb1ddb62c21a9eae90daf97d275b8bf Mon Sep 17 00:00:00 2001 +From: Debarshi Ray +Date: Thu, 28 May 2015 15:51:23 +0200 +Subject: [PATCH 07/12] daemon: Check & refresh credentials during startup and + network changes + +https://bugzilla.gnome.org/show_bug.cgi?id=693578 +--- + src/daemon/goadaemon.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 101 insertions(+), 2 deletions(-) + +diff --git a/src/daemon/goadaemon.c b/src/daemon/goadaemon.c +index f933e69..efa7ba7 100644 +--- a/src/daemon/goadaemon.c ++++ b/src/daemon/goadaemon.c +@@ -36,11 +36,14 @@ struct _GoaDaemon + GFileMonitor *home_conf_file_monitor; + GFileMonitor *home_conf_dir_monitor; + ++ GNetworkMonitor *network_monitor; ++ + GDBusObjectManagerServer *object_manager; + + GoaManager *manager; + + guint config_timeout_id; ++ guint credentials_timeout_id; + }; + + typedef struct +@@ -71,6 +74,7 @@ static gboolean on_account_handle_ensure_credentials (GoaAccount *acc + GDBusMethodInvocation *invocation, + gpointer user_data); + ++static void goa_daemon_check_credentials (GoaDaemon *self); + static void goa_daemon_reload_configuration (GoaDaemon *self); + + G_DEFINE_TYPE (GoaDaemon, goa_daemon, G_TYPE_OBJECT); +@@ -85,6 +89,11 @@ goa_daemon_finalize (GObject *object) + g_source_remove (self->config_timeout_id); + } + ++ if (self->credentials_timeout_id != 0) ++ { ++ g_source_remove (self->credentials_timeout_id); ++ } ++ + if (self->system_conf_dir_monitor != NULL) + { + g_signal_handlers_disconnect_by_func (self->system_conf_dir_monitor, on_file_monitor_changed, self); +@@ -162,6 +171,35 @@ on_file_monitor_changed (GFileMonitor *monitor, + } + } + ++static gboolean ++on_check_credentials_timeout (gpointer user_data) ++{ ++ GoaDaemon *self = GOA_DAEMON (user_data); ++ ++ self->credentials_timeout_id = 0; ++ g_info ("Checking credentials\n"); ++ goa_daemon_check_credentials (self); ++ ++ return G_SOURCE_REMOVE; ++} ++ ++static void ++queue_check_credentials (GoaDaemon *self) ++{ ++ if (self->credentials_timeout_id != 0) ++ { ++ g_source_remove (self->credentials_timeout_id); ++ } ++ ++ self->credentials_timeout_id = g_timeout_add_seconds (1, on_check_credentials_timeout, self); ++} ++ ++static void ++on_network_monitor_network_changed (GoaDaemon *self, gboolean available) ++{ ++ queue_check_credentials (self); ++} ++ + #ifdef GOA_KERBEROS_ENABLED + static void + activate_identity_service (GoaDaemon *self) +@@ -230,9 +268,18 @@ goa_daemon_init (GoaDaemon *self) + /* prime the list of accounts */ + goa_daemon_reload_configuration (self); + ++ self->network_monitor = g_network_monitor_get_default (); ++ g_signal_connect_object (self->network_monitor, ++ "network-changed", ++ G_CALLBACK (on_network_monitor_network_changed), ++ self, ++ G_CONNECT_SWAPPED); ++ + /* Export objects */ + g_dbus_object_manager_server_set_connection (self->object_manager, self->connection); + ++ queue_check_credentials (self); ++ + #ifdef GOA_KERBEROS_ENABLED + activate_identity_service (self); + #endif +@@ -1123,7 +1170,14 @@ ensure_credentials_cb (GoaProvider *provider, + error->message, g_quark_to_string (error->domain), error->code); + } + } +- g_dbus_method_invocation_take_error (data->invocation, error); ++ ++ if (data->invocation != NULL) ++ { ++ g_dbus_method_invocation_take_error (data->invocation, error); ++ error = NULL; ++ } ++ ++ g_clear_error (&error); + } + else + { +@@ -1138,7 +1192,9 @@ ensure_credentials_cb (GoaProvider *provider, + g_message ("%s: Setting AttentionNeeded to FALSE because EnsureCredentials() succeded\n", + g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object))); + } +- goa_account_complete_ensure_credentials (account, data->invocation, expires_in); ++ ++ if (data->invocation != NULL) ++ goa_account_complete_ensure_credentials (account, data->invocation, expires_in); + } + ensure_data_unref (data); + } +@@ -1175,3 +1231,46 @@ on_account_handle_ensure_credentials (GoaAccount *account, + g_clear_object (&provider); + return TRUE; /* invocation was handled */ + } ++ ++/* ++ * goa_daemon_check_credentials: ++ * @self: A #GoaDaemon ++ * ++ * Checks whether credentials are valid and tries to refresh them if ++ * not. It also reports whether accounts are usable with the current ++ * network. ++ */ ++static void ++goa_daemon_check_credentials (GoaDaemon *self) ++{ ++ GList *l; ++ GList *objects; ++ ++ objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (self->object_manager)); ++ for (l = objects; l != NULL; l = l->next) ++ { ++ GoaAccount *account; ++ GoaObject *object = GOA_OBJECT (l->data); ++ GoaProvider *provider = NULL; ++ const gchar *provider_type; ++ ++ account = goa_object_peek_account (object); ++ if (account == NULL) ++ continue; ++ ++ provider_type = goa_account_get_provider_type (account); ++ provider = goa_provider_get_for_provider_type (provider_type); ++ if (provider == NULL) ++ continue; ++ ++ goa_provider_ensure_credentials (provider, ++ object, ++ NULL, /* GCancellable */ ++ (GAsyncReadyCallback) ensure_credentials_cb, ++ ensure_data_new (self, object, NULL)); ++ ++ g_clear_object (&provider); ++ } ++ ++ g_list_free_full (objects, g_object_unref); ++} +-- +2.1.0 + + +From f261c93bfddfc96f261a7388d1c46524d408d4e6 Mon Sep 17 00:00:00 2001 +From: Debarshi Ray +Date: Thu, 28 May 2015 16:20:57 +0200 +Subject: [PATCH 08/12] kerberos: Mark EnsureCredentials failures as + authorization errors + +Otherwise GoaAccount:attention-needed won't be set and the UI won't +reflect reality. + +Fall out from 7ba73645e6068935f331969e14d56a39544ebca5 + +https://bugzilla.gnome.org/show_bug.cgi?id=693578 +--- + src/goabackend/goakerberosprovider.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/src/goabackend/goakerberosprovider.c b/src/goabackend/goakerberosprovider.c +index 2eb6b67..33dc1ad 100644 +--- a/src/goabackend/goakerberosprovider.c ++++ b/src/goabackend/goakerberosprovider.c +@@ -1406,18 +1406,29 @@ ensure_credentials_sync (GoaProvider *provider, + + if (identity == NULL || !goa_identity_service_identity_get_is_signed_in (identity)) + { ++ GError *lookup_error; + gboolean ticket_synced; + ++ lookup_error = NULL; ++ + g_mutex_unlock (&identity_manager_mutex); + ticket_synced = get_ticket_sync (GOA_KERBEROS_PROVIDER (provider), + object, + FALSE /* Don't allow interaction */, + cancellable, +- error); ++ &lookup_error); + g_mutex_lock (&identity_manager_mutex); + + if (!ticket_synced) +- goto out; ++ { ++ translate_error (&lookup_error); ++ g_set_error_literal (error, ++ GOA_ERROR, ++ GOA_ERROR_NOT_AUTHORIZED, ++ lookup_error->message); ++ g_error_free (lookup_error); ++ goto out; ++ } + + if (identity == NULL) + identity = get_identity_from_object_manager (GOA_KERBEROS_PROVIDER (provider), +-- +2.1.0 + + +From 77f5b03632b779499e29b2e91c55a562c362cfc9 Mon Sep 17 00:00:00 2001 +From: Debarshi Ray +Date: Fri, 29 May 2015 15:40:32 +0200 +Subject: [PATCH 09/12] client, identity: Use g_list_free_full wherever + applicable + +https://bugzilla.gnome.org/show_bug.cgi?id=693578 +--- + src/goa/goaclient.c | 3 +-- + src/goaidentity/goakerberosidentitymanager.c | 3 +-- + 2 files changed, 2 insertions(+), 4 deletions(-) + +diff --git a/src/goa/goaclient.c b/src/goa/goaclient.c +index 89d52c8..20d6e88 100644 +--- a/src/goa/goaclient.c ++++ b/src/goa/goaclient.c +@@ -471,8 +471,7 @@ goa_client_get_accounts (GoaClient *client) + if (goa_object_peek_account (object) != NULL) + ret = g_list_prepend (ret, g_object_ref (object)); + } +- g_list_foreach (objects, (GFunc) g_object_unref, NULL); +- g_list_free (objects); ++ g_list_free_full (objects, g_object_unref); + + return ret; + } +diff --git a/src/goaidentity/goakerberosidentitymanager.c b/src/goaidentity/goakerberosidentitymanager.c +index a1898c9..162cf3f 100644 +--- a/src/goaidentity/goakerberosidentitymanager.c ++++ b/src/goaidentity/goakerberosidentitymanager.c +@@ -594,8 +594,7 @@ identity_sort_func (GoaIdentity *a, + static void + free_identity_list (GList *list) + { +- g_list_foreach (list, (GFunc) g_object_unref, NULL); +- g_list_free (list); ++ g_list_free_full (list, g_object_unref); + } + + static void +-- +2.1.0 + + +From 3939e2be726b532dba0debfc3d4b933ae8d54e1a Mon Sep 17 00:00:00 2001 +From: Debarshi Ray +Date: Fri, 29 May 2015 15:45:10 +0200 +Subject: [PATCH 10/12] identity: Simplify the destruction + +GoaKerberosIdentityQuery doesn't hold any references so there is no +need to free the list in dispose. We can use the dummy finalize that we +already have and avoid the complexity. + +https://bugzilla.gnome.org/show_bug.cgi?id=693578 +--- + src/goaidentity/goakerberosidentityinquiry.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/goaidentity/goakerberosidentityinquiry.c b/src/goaidentity/goakerberosidentityinquiry.c +index 7c9a84a..4560b35 100644 +--- a/src/goaidentity/goakerberosidentityinquiry.c ++++ b/src/goaidentity/goakerberosidentityinquiry.c +@@ -102,15 +102,15 @@ goa_kerberos_identity_inquiry_dispose (GObject *object) + g_clear_object (&self->priv->identity); + g_clear_pointer (&self->priv->name, (GDestroyNotify) g_free); + g_clear_pointer (&self->priv->banner, (GDestroyNotify) g_free); +- +- g_list_foreach (self->priv->queries, +- (GFunc) goa_kerberos_identity_query_free, NULL); +- g_clear_pointer (&self->priv->queries, (GDestroyNotify) g_list_free); + } + + static void + goa_kerberos_identity_inquiry_finalize (GObject *object) + { ++ GoaKerberosIdentityInquiry *self = GOA_KERBEROS_IDENTITY_INQUIRY (object); ++ ++ g_list_free_full (self->priv->queries, (GDestroyNotify) goa_kerberos_identity_query_free); ++ + G_OBJECT_CLASS (goa_kerberos_identity_inquiry_parent_class)->finalize (object); + } + +-- +2.1.0 + + +From b7340b085604b291f4f894fe747ab109c19edc03 Mon Sep 17 00:00:00 2001 +From: Debarshi Ray +Date: Fri, 29 May 2015 15:46:09 +0200 +Subject: [PATCH 11/12] identity: Chain up during dispose + +https://bugzilla.gnome.org/show_bug.cgi?id=693578 +--- + src/goaidentity/goakerberosidentityinquiry.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/goaidentity/goakerberosidentityinquiry.c b/src/goaidentity/goakerberosidentityinquiry.c +index 4560b35..67a8a60 100644 +--- a/src/goaidentity/goakerberosidentityinquiry.c ++++ b/src/goaidentity/goakerberosidentityinquiry.c +@@ -102,6 +102,8 @@ goa_kerberos_identity_inquiry_dispose (GObject *object) + g_clear_object (&self->priv->identity); + g_clear_pointer (&self->priv->name, (GDestroyNotify) g_free); + g_clear_pointer (&self->priv->banner, (GDestroyNotify) g_free); ++ ++ G_OBJECT_CLASS (goa_kerberos_identity_inquiry_parent_class)->dispose (object); + } + + static void +-- +2.1.0 + + +From 59061d81175411c2b38c4d87dfd94b0f3893b765 Mon Sep 17 00:00:00 2001 +From: Debarshi Ray +Date: Fri, 29 May 2015 17:51:33 +0200 +Subject: [PATCH 12/12] kerberos: Don't leak the GCancellable + +--- + src/goabackend/goakerberosprovider.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/src/goabackend/goakerberosprovider.c b/src/goabackend/goakerberosprovider.c +index 33dc1ad..69a1c91 100644 +--- a/src/goabackend/goakerberosprovider.c ++++ b/src/goabackend/goakerberosprovider.c +@@ -990,9 +990,10 @@ perform_initial_sign_in (GoaKerberosProvider *self, + object); + g_simple_async_result_set_check_cancellable (operation_result, cancellable); + +- g_object_set_data (G_OBJECT (operation_result), +- "cancellable", +- cancellable); ++ g_object_set_data_full (G_OBJECT (operation_result), ++ "cancellable", ++ g_object_ref (cancellable), ++ g_object_unref); + g_object_set_data (G_OBJECT (operation_result), + "principal", + (gpointer) +@@ -1003,6 +1004,8 @@ perform_initial_sign_in (GoaKerberosProvider *self, + (GAsyncReadyCallback) + on_system_prompt_open_for_initial_sign_in, + operation_result); ++ ++ g_object_unref (cancellable); + } + + static char * +-- +2.1.0 + diff --git a/SOURCES/facebook-updates-and-fixes.patch b/SOURCES/facebook-updates-and-fixes.patch deleted file mode 100644 index fa8bc78..0000000 --- a/SOURCES/facebook-updates-and-fixes.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 4df087b50116b9b0a0b8480f2bdb2ad61d1408a9 Mon Sep 17 00:00:00 2001 -From: Debarshi Ray -Date: Mon, 31 Mar 2014 17:31:06 +0200 -Subject: [PATCH 1/2] facebook: Update README - -Facebook changed the layout of their OAuth2 developer documentation -website. Add new URLs with information relevant to us. - -Fixes: https://bugzilla.gnome.org/726609 ---- - README | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/README b/README -index d8d201a..0b6c32d 100644 ---- a/README -+++ b/README -@@ -5,7 +5,11 @@ GNOME Online Accounts - Single sign-on framework for GNOME - Facebook - -------- - --OAuth 2.0: https://developers.facebook.com/docs/authentication/ -+OAuth 2.0: -+https://developers.facebook.com/docs/authentication/ -+https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow -+https://developers.facebook.com/docs/reference/dialogs/oauth/ -+ - Scopes: https://developers.facebook.com/docs/authentication/permissions/ - - Notes: --- -1.8.5.3 - - -From 895b77e9b704f23294d39307cb0d38a719eff72b Mon Sep 17 00:00:00 2001 -From: Debarshi Ray -Date: Mon, 31 Mar 2014 18:06:58 +0200 -Subject: [PATCH 2/2] facebook: Update the code to request a compact web UI - -Earlier we were using m.facebook.com as the host in the authorization -URI. That does not work anymore. Now we need to use www.facebook.com -and display=popup. - -According to: -https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow -https://developers.facebook.com/docs/reference/dialogs/oauth/ - -Fixes: https://bugzilla.gnome.org/726609 ---- - src/goabackend/goafacebookprovider.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/src/goabackend/goafacebookprovider.c b/src/goabackend/goafacebookprovider.c -index 5dc5e60..21da0e7 100644 ---- a/src/goabackend/goafacebookprovider.c -+++ b/src/goabackend/goafacebookprovider.c -@@ -1,6 +1,6 @@ - /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - /* -- * Copyright (C) 2011, 2012 Red Hat, Inc. -+ * Copyright (C) 2011, 2012, 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 -@@ -101,6 +101,7 @@ build_authorization_uri (GoaOAuth2Provider *provider, - - uri = g_strdup_printf ("%s" - "?response_type=token" -+ "&display=popup" - "&redirect_uri=%s" - "&client_id=%s" - "&scope=%s", -@@ -114,7 +115,7 @@ build_authorization_uri (GoaOAuth2Provider *provider, - static const gchar * - get_authorization_uri (GoaOAuth2Provider *provider) - { -- return "https://m.facebook.com/dialog/oauth"; -+ return "https://www.facebook.com/dialog/oauth"; - } - - static const gchar * --- -1.8.5.3 - diff --git a/SOURCES/google-drop-password-based.patch b/SOURCES/google-drop-password-based.patch deleted file mode 100644 index 2aadd62..0000000 --- a/SOURCES/google-drop-password-based.patch +++ /dev/null @@ -1,421 +0,0 @@ -From 34b900e7e4aad8b0454649dab0b4ebaaddb2adc4 Mon Sep 17 00:00:00 2001 -From: Debarshi Ray -Date: Tue, 11 Jun 2013 16:58:21 +0200 -Subject: [PATCH 1/3] google: Bump credentials generation - -Access to the following were turned on in the Google APIs Console: - - Calendar API - - Google Calendar CalDAV API - - Google Contacts CardDAV API - -Of these, only the last two are new. We were already requesting the -scope for Calendar API, but looks like the APIs Console is the way -to go now. Interestingly the APIs Console does not list all the other -services that we are interested in, or it is does but is not obvious -to me. - -In any case we need access to their new CalDAV API which works with -OAuth2 because that would let us work with 2-factor authenticated -accounts again. - -See: https://bugzilla.gnome.org/show_bug.cgi?id=686804 - https://bugzilla.gnome.org/show_bug.cgi?id=688364 ---- - src/goabackend/goagoogleprovider.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/goabackend/goagoogleprovider.c b/src/goabackend/goagoogleprovider.c -index b3accdb..1c5c04b 100644 ---- a/src/goabackend/goagoogleprovider.c -+++ b/src/goabackend/goagoogleprovider.c -@@ -137,7 +137,7 @@ get_scope (GoaOAuth2Provider *provider) - static guint - get_credentials_generation (GoaProvider *provider) - { -- return 3; -+ return 4; - } - - static const gchar * --- -1.8.4.2 - - -From 930a86add739b065b2cc43e2efae7fa30dfeee07 Mon Sep 17 00:00:00 2001 -From: Debarshi Ray -Date: Wed, 19 Jun 2013 17:04:38 +0200 -Subject: [PATCH 2/3] google: Export CalDAV and CardDAV endpoints - -According to: -https://developers.google.com/google-apps/calendar/caldav/v2/guide/ -https://developers.google.com/google-apps/carddav/ - -See: https://bugzilla.gnome.org/show_bug.cgi?id=686804 - https://bugzilla.gnome.org/show_bug.cgi?id=688364 ---- - src/goabackend/goagoogleprovider.c | 18 ++++++++++++++++-- - 1 file changed, 16 insertions(+), 2 deletions(-) - -diff --git a/src/goabackend/goagoogleprovider.c b/src/goabackend/goagoogleprovider.c -index 1c5c04b..5b413f7 100644 ---- a/src/goabackend/goagoogleprovider.c -+++ b/src/goabackend/goagoogleprovider.c -@@ -355,6 +355,7 @@ build_object (GoaProvider *provider, - gboolean contacts_enabled; - gboolean chat_enabled; - gboolean documents_enabled; -+ const gchar *email_address; - - account = NULL; - mail = NULL; -@@ -389,6 +390,7 @@ build_object (GoaProvider *provider, - } - - account = goa_object_get_account (GOA_OBJECT (object)); -+ email_address = goa_account_get_identity (account); - - /* Email */ - mail = goa_object_get_mail (GOA_OBJECT (object)); -@@ -397,8 +399,6 @@ build_object (GoaProvider *provider, - { - if (mail == NULL) - { -- const gchar *email_address; -- email_address = goa_account_get_identity (account); - mail = goa_mail_skeleton_new (); - g_object_set (G_OBJECT (mail), - "email-address", email_address, -@@ -428,8 +428,19 @@ build_object (GoaProvider *provider, - { - if (calendar == NULL) - { -+ gchar *uri_caldav; -+ -+ uri_caldav = g_strconcat ("https://apidata.googleusercontent.com/caldav/v2/", -+ email_address, -+ "/user", -+ NULL); -+ - calendar = goa_calendar_skeleton_new (); -+ g_object_set (G_OBJECT (calendar), -+ "uri", uri_caldav, -+ NULL); - goa_object_skeleton_set_calendar (object, calendar); -+ g_free (uri_caldav); - } - } - else -@@ -446,6 +457,9 @@ build_object (GoaProvider *provider, - if (contacts == NULL) - { - contacts = goa_contacts_skeleton_new (); -+ g_object_set (G_OBJECT (contacts), -+ "uri", "https://www.googleapis.com/.well-known/carddav", -+ NULL); - goa_object_skeleton_set_contacts (object, contacts); - } - } --- -1.8.4.2 - - -From e3a72091bca2d48ee3c87530b0d8b30d87c21ff0 Mon Sep 17 00:00:00 2001 -From: Debarshi Ray -Date: Fri, 28 Jun 2013 14:22:07 +0200 -Subject: [PATCH 3/3] google: Don't offer a PasswordBased interface - -This was a temporary measure back when Google did not support OAuth2 -for CalDAV. Now that they do, we can drop this. - -In any case, the workaround didn't work with accounts using 2-factor -authentication. This will make those people happy. - -This reverts 89c335479c1bb8409af8296c99ffea602a28b71f - -See: https://bugzilla.gnome.org/show_bug.cgi?id=686804 - https://bugzilla.gnome.org/show_bug.cgi?id=688364 ---- - src/goabackend/goagoogleprovider.c | 215 ------------------------------------- - 1 file changed, 215 deletions(-) - -diff --git a/src/goabackend/goagoogleprovider.c b/src/goabackend/goagoogleprovider.c -index 5b413f7..065845d 100644 ---- a/src/goabackend/goagoogleprovider.c -+++ b/src/goabackend/goagoogleprovider.c -@@ -32,8 +32,6 @@ - #include "goaprovider-priv.h" - #include "goaoauth2provider.h" - #include "goagoogleprovider.h" --#include "goahttpclient.h" --#include "goautils.h" - - /** - * GoaGoogleProvider: -@@ -71,8 +69,6 @@ G_DEFINE_TYPE_WITH_CODE (GoaGoogleProvider, goa_google_provider, GOA_TYPE_OAUTH2 - - /* ---------------------------------------------------------------------------------------------------- */ - --static const gchar *CALDAV_ENDPOINT = "https://www.google.com/calendar/dav/%s/events/"; -- - static const gchar * - get_provider_type (GoaProvider *_provider) - { -@@ -291,48 +287,8 @@ is_identity_node (GoaOAuth2Provider *provider, WebKitDOMHTMLInputElement *elemen - return ret; - } - --static gboolean --is_password_node (GoaOAuth2Provider *provider, WebKitDOMHTMLInputElement *element) --{ -- gboolean ret; -- gchar *element_type; -- gchar *id; -- gchar *name; -- -- element_type = NULL; -- id = NULL; -- name = NULL; -- -- ret = FALSE; -- -- g_object_get (element, "type", &element_type, NULL); -- if (g_strcmp0 (element_type, "password") != 0) -- goto out; -- -- id = webkit_dom_html_element_get_id (WEBKIT_DOM_HTML_ELEMENT (element)); -- if (g_strcmp0 (id, "Passwd") != 0) -- goto out; -- -- name = webkit_dom_html_input_element_get_name (element); -- if (g_strcmp0 (name, "Passwd") != 0) -- goto out; -- -- ret = TRUE; -- -- out: -- g_free (element_type); -- g_free (id); -- g_free (name); -- return ret; --} -- - /* ---------------------------------------------------------------------------------------------------- */ - --static gboolean on_handle_get_password (GoaPasswordBased *interface, -- GDBusMethodInvocation *invocation, -- const gchar *id, -- gpointer user_data); -- - static gboolean - build_object (GoaProvider *provider, - GoaObjectSkeleton *object, -@@ -348,7 +304,6 @@ build_object (GoaProvider *provider, - GoaContacts *contacts; - GoaChat *chat; - GoaDocuments *documents; -- GoaPasswordBased *password_based; - gboolean ret; - gboolean mail_enabled; - gboolean calendar_enabled; -@@ -375,20 +330,6 @@ build_object (GoaProvider *provider, - error)) - goto out; - -- password_based = goa_object_get_password_based (GOA_OBJECT (object)); -- if (password_based == NULL) -- { -- password_based = goa_password_based_skeleton_new (); -- /* Ensure D-Bus method invocations run in their own thread */ -- g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (password_based), -- G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD); -- goa_object_skeleton_set_password_based (object, password_based); -- g_signal_connect (password_based, -- "handle-get-password", -- G_CALLBACK (on_handle_get_password), -- NULL); -- } -- - account = goa_object_get_account (GOA_OBJECT (object)); - email_address = goa_account_get_identity (account); - -@@ -549,103 +490,6 @@ build_object (GoaProvider *provider, - /* ---------------------------------------------------------------------------------------------------- */ - - static gboolean --ensure_credentials_sync (GoaProvider *provider, -- GoaObject *object, -- gint *out_expires_in, -- GCancellable *cancellable, -- GError **error) --{ -- GVariant *credentials; -- GoaAccount *account; -- GoaHttpClient *http_client; -- gboolean ret; -- const gchar *username; -- gchar *password; -- gchar *uri_caldav; -- -- credentials = NULL; -- http_client = NULL; -- password = NULL; -- uri_caldav = NULL; -- -- ret = FALSE; -- -- /* Chain up */ -- if (!GOA_PROVIDER_CLASS (goa_google_provider_parent_class)->ensure_credentials_sync (provider, -- object, -- out_expires_in, -- cancellable, -- error)) -- goto out; -- -- credentials = goa_utils_lookup_credentials_sync (provider, -- object, -- cancellable, -- error); -- if (credentials == NULL) -- { -- if (error != NULL) -- { -- (*error)->domain = GOA_ERROR; -- (*error)->code = GOA_ERROR_NOT_AUTHORIZED; -- } -- goto out; -- } -- -- account = goa_object_peek_account (object); -- username = goa_account_get_presentation_identity (account); -- uri_caldav = g_strdup_printf (CALDAV_ENDPOINT, username); -- -- if (!g_variant_lookup (credentials, "password", "s", &password)) -- { -- if (error != NULL) -- { -- *error = g_error_new (GOA_ERROR, -- GOA_ERROR_NOT_AUTHORIZED, -- _("Did not find password with identity `%s' in credentials"), -- username); -- } -- goto out; -- } -- -- http_client = goa_http_client_new (); -- ret = goa_http_client_check_sync (http_client, -- uri_caldav, -- username, -- password, -- FALSE, -- cancellable, -- error); -- if (!ret) -- { -- if (error != NULL) -- { -- g_prefix_error (error, -- /* Translators: the first %s is the username -- * (eg., debarshi.ray@gmail.com or rishi), and the -- * (%s, %d) is the error domain and code. -- */ -- _("Invalid password with username `%s' (%s, %d): "), -- username, -- g_quark_to_string ((*error)->domain), -- (*error)->code); -- (*error)->domain = GOA_ERROR; -- (*error)->code = GOA_ERROR_NOT_AUTHORIZED; -- } -- goto out; -- } -- -- out: -- g_clear_object (&http_client); -- g_free (password); -- g_free (uri_caldav); -- g_clear_pointer (&credentials, (GDestroyNotify) g_variant_unref); -- return ret; --} -- --/* ---------------------------------------------------------------------------------------------------- */ -- --static gboolean - get_use_mobile_browser (GoaOAuth2Provider *provider) - { - return TRUE; -@@ -726,7 +570,6 @@ goa_google_provider_class_init (GoaGoogleProviderClass *klass) - provider_class->get_provider_name = get_provider_name; - provider_class->get_provider_group = get_provider_group; - provider_class->build_object = build_object; -- provider_class->ensure_credentials_sync = ensure_credentials_sync; - provider_class->show_account = show_account; - provider_class->get_credentials_generation = get_credentials_generation; - -@@ -740,65 +583,7 @@ goa_google_provider_class_init (GoaGoogleProviderClass *klass) - oauth2_class->get_scope = get_scope; - oauth2_class->is_deny_node = is_deny_node; - oauth2_class->is_identity_node = is_identity_node; -- oauth2_class->is_password_node = is_password_node; - oauth2_class->get_token_uri = get_token_uri; - oauth2_class->get_use_mobile_browser = get_use_mobile_browser; - oauth2_class->add_account_key_values = add_account_key_values; - } -- --/* ---------------------------------------------------------------------------------------------------- */ -- --/* runs in a thread dedicated to handling @invocation */ --static gboolean --on_handle_get_password (GoaPasswordBased *interface, -- GDBusMethodInvocation *invocation, -- const gchar *id, /* unused */ -- gpointer user_data) --{ -- GoaObject *object; -- GoaAccount *account; -- GoaProvider *provider; -- GError *error; -- GVariant *credentials; -- const gchar *identity; -- gchar *password; -- -- /* TODO: maybe log what app is requesting access */ -- -- password = NULL; -- credentials = NULL; -- -- object = GOA_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (interface))); -- account = goa_object_peek_account (object); -- identity = goa_account_get_identity (account); -- provider = goa_provider_get_for_provider_type (goa_account_get_provider_type (account)); -- -- error = NULL; -- credentials = goa_utils_lookup_credentials_sync (provider, -- object, -- NULL, /* GCancellable* */ -- &error); -- if (credentials == NULL) -- { -- g_dbus_method_invocation_take_error (invocation, error); -- goto out; -- } -- -- if (!g_variant_lookup (credentials, "password", "s", &password)) -- { -- g_dbus_method_invocation_return_error (invocation, -- GOA_ERROR, -- GOA_ERROR_FAILED, /* TODO: more specific */ -- _("Did not find password with identity `%s' in credentials"), -- identity); -- goto out; -- } -- -- goa_password_based_complete_get_password (interface, invocation, password); -- -- out: -- g_free (password); -- g_clear_pointer (&credentials, (GDestroyNotify) g_variant_unref); -- g_object_unref (provider); -- return TRUE; /* invocation was handled */ --} --- -1.8.4.2 - diff --git a/SOURCES/kerberos-fix-renewal.patch b/SOURCES/kerberos-fix-renewal.patch new file mode 100644 index 0000000..8465fa5 --- /dev/null +++ b/SOURCES/kerberos-fix-renewal.patch @@ -0,0 +1,851 @@ +From 3d9361b917ef923f39ba54835512171d83e457b7 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Tue, 22 Sep 2015 14:33:35 -0400 +Subject: [PATCH 1/3] identity: consider ticket start time when calculating + renewal time + +Right now we try to renew the kerberos ticket at the midpoint between +when we first set up the renewal alarm and when the ticket expires. + +Unfortunately, this doesn't work for kernel keyring based kerberos +tickets, since the alarms are reset on a regular interval (as part +of the polling process to check for updates, since kernel keyring +doesn't have changed notification). Since the alarms are reset +regularly, the midpoint converges toward the end of the ticket +lifetime. + +Instead, we should consider the ticket start time, which remains +constant. This commit tracks the ticket start time, and changes +the code renewal alarm to use the mid point between the start time +and expiration time of the ticket. +--- + src/goaidentity/goaidentity.c | 7 +++++ + src/goaidentity/goakerberosidentity.c | 55 +++++++++++++++++++++++++++++------ + 2 files changed, 53 insertions(+), 9 deletions(-) + +diff --git a/src/goaidentity/goaidentity.c b/src/goaidentity/goaidentity.c +index 2fc491b..2904e2a 100644 +--- a/src/goaidentity/goaidentity.c ++++ b/src/goaidentity/goaidentity.c +@@ -13,60 +13,67 @@ + * 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 . + */ + + #include "config.h" + + #include + #include + + #include "goaidentity.h" + + G_DEFINE_INTERFACE (GoaIdentity, goa_identity, G_TYPE_OBJECT); + + static void + goa_identity_default_init (GoaIdentityInterface *interface) + { + g_object_interface_install_property (interface, + g_param_spec_string ("identifier", + "identifier", + "identifier", + NULL, G_PARAM_READABLE)); + g_object_interface_install_property (interface, + g_param_spec_boolean ("is-signed-in", + "Is signed in", + "Whether or not identity is currently signed in", + FALSE, + G_PARAM_READABLE)); + g_object_interface_install_property (interface, ++ g_param_spec_int64 ("start-timestamp", ++ "Start Timestamp", ++ "A timestamp of when the identities credentials first became valid", ++ -1, ++ G_MAXINT64, ++ -1, G_PARAM_READABLE)); ++ g_object_interface_install_property (interface, + g_param_spec_int64 ("expiration-timestamp", + "Expiration Timestamp", + "A timestamp of when the identities credentials expire", + -1, + G_MAXINT64, + -1, G_PARAM_READABLE)); + } + + GQuark + goa_identity_error_quark (void) + { + static GQuark error_quark = 0; + + if (error_quark == 0) + { + error_quark = g_quark_from_static_string ("goa-identity-error"); + } + + return error_quark; + } + + const char * + goa_identity_get_identifier (GoaIdentity *self) + { + return GOA_IDENTITY_GET_IFACE (self)->get_identifier (self); + } + + gboolean + goa_identity_is_signed_in (GoaIdentity *self) + { +diff --git a/src/goaidentity/goakerberosidentity.c b/src/goaidentity/goakerberosidentity.c +index 4370a09..6865535 100644 +--- a/src/goaidentity/goakerberosidentity.c ++++ b/src/goaidentity/goakerberosidentity.c +@@ -22,86 +22,89 @@ + #include "goakerberosidentity.h" + #include "goakerberosidentityinquiry.h" + #include "goaalarm.h" + + #include + #include + #include + + #include + #include + #include + + typedef enum + { + VERIFICATION_LEVEL_UNVERIFIED, + VERIFICATION_LEVEL_ERROR, + VERIFICATION_LEVEL_EXISTS, + VERIFICATION_LEVEL_SIGNED_IN + } VerificationLevel; + + struct _GoaKerberosIdentityPrivate + { + krb5_context kerberos_context; + krb5_ccache credentials_cache; + + char *identifier; + guint identifier_idle_id; + + char *preauth_identity_source; + ++ krb5_timestamp start_time; ++ guint start_time_idle_id; + krb5_timestamp expiration_time; + guint expiration_time_idle_id; + + GoaAlarm *expiration_alarm; + GoaAlarm *expiring_alarm; + GoaAlarm *renewal_alarm; + + VerificationLevel cached_verification_level; + guint is_signed_in_idle_id; + }; + + enum + { + EXPIRING, + EXPIRED, + UNEXPIRED, + NEEDS_RENEWAL, + NEEDS_REFRESH, + NUMBER_OF_SIGNALS, + }; + + enum + { + PROP_0, + PROP_IDENTIFIER, + PROP_IS_SIGNED_IN, ++ PROP_START_TIMESTAMP, + PROP_EXPIRATION_TIMESTAMP + }; + + static guint signals[NUMBER_OF_SIGNALS] = { 0 }; + + static void identity_interface_init (GoaIdentityInterface *interface); + static void initable_interface_init (GInitableIface *interface); + static void reset_alarms (GoaKerberosIdentity *self); + static void clear_alarms (GoaKerberosIdentity *self); + static gboolean goa_kerberos_identity_is_signed_in (GoaIdentity *identity); + static void set_error_from_krb5_error_code (GoaKerberosIdentity *self, + GError **error, + gint code, + krb5_error_code error_code, + const char *format, + ...); + + G_LOCK_DEFINE_STATIC (identity_lock); + + G_DEFINE_TYPE_WITH_CODE (GoaKerberosIdentity, + goa_kerberos_identity, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, + initable_interface_init) + G_IMPLEMENT_INTERFACE (GOA_TYPE_IDENTITY, + identity_interface_init)); + static void + goa_kerberos_identity_dispose (GObject *object) + { + GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (object); +@@ -121,60 +124,65 @@ goa_kerberos_identity_finalize (GObject *object) + { + GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (object); + + g_free (self->priv->identifier); + + if (self->priv->credentials_cache != NULL) + krb5_cc_close (self->priv->kerberos_context, self->priv->credentials_cache); + + G_OBJECT_CLASS (goa_kerberos_identity_parent_class)->finalize (object); + } + + static void + goa_kerberos_identity_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *param_spec) + { + GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (object); + + switch (property_id) + { + case PROP_IDENTIFIER: + G_LOCK (identity_lock); + g_value_set_string (value, self->priv->identifier); + G_UNLOCK (identity_lock); + break; + case PROP_IS_SIGNED_IN: + g_value_set_boolean (value, + goa_kerberos_identity_is_signed_in (GOA_IDENTITY (self))); + break; ++ case PROP_START_TIMESTAMP: ++ G_LOCK (identity_lock); ++ g_value_set_int64 (value, (gint64) self->priv->start_time); ++ G_UNLOCK (identity_lock); ++ break; + case PROP_EXPIRATION_TIMESTAMP: + G_LOCK (identity_lock); + g_value_set_int64 (value, (gint64) self->priv->expiration_time); + G_UNLOCK (identity_lock); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec); + break; + } + } + + static void + goa_kerberos_identity_class_init (GoaKerberosIdentityClass *klass) + { + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = goa_kerberos_identity_dispose; + object_class->finalize = goa_kerberos_identity_finalize; + object_class->get_property = goa_kerberos_identity_get_property; + + g_type_class_add_private (klass, sizeof (GoaKerberosIdentityPrivate)); + + signals[EXPIRING] = g_signal_new ("expiring", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, +@@ -194,60 +202,63 @@ goa_kerberos_identity_class_init (GoaKerberosIdentityClass *klass) + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 0); + signals[NEEDS_RENEWAL] = g_signal_new ("needs-renewal", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 0); + signals[NEEDS_REFRESH] = g_signal_new ("needs-refresh", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 0); + + g_object_class_override_property (object_class, PROP_IDENTIFIER, "identifier"); + g_object_class_override_property (object_class, PROP_IS_SIGNED_IN, "is-signed-in"); + g_object_class_override_property (object_class, ++ PROP_START_TIMESTAMP, ++ "start-timestamp"); ++ g_object_class_override_property (object_class, + PROP_EXPIRATION_TIMESTAMP, + "expiration-timestamp"); + + } + + static char * + get_identifier (GoaKerberosIdentity *self, + GError **error) + { + krb5_principal principal; + krb5_error_code error_code; + char *unparsed_name; + char *identifier = NULL; + + if (self->priv->credentials_cache == NULL) + return NULL; + + error_code = krb5_cc_get_principal (self->priv->kerberos_context, + self->priv->credentials_cache, + &principal); + + if (error_code != 0) + { + if (error_code == KRB5_CC_END) + { + set_error_from_krb5_error_code (self, + error, + GOA_IDENTITY_ERROR_CREDENTIALS_UNAVAILABLE, + error_code, + _ +@@ -546,207 +557,233 @@ on_notify_queued (NotifyRequest *request) + + return FALSE; + } + + static void + queue_notify (GoaKerberosIdentity *self, + guint *idle_id, + const char *property_name) + { + NotifyRequest *request; + + if (*idle_id != 0) + { + return; + } + + request = g_slice_new0 (NotifyRequest); + request->self = g_object_ref (self); + request->idle_id = idle_id; + request->property_name = property_name; + + *idle_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, + (GSourceFunc) + on_notify_queued, + request, + (GDestroyNotify) + clear_idle_id); + } + + static void ++set_start_time (GoaKerberosIdentity *self, ++ krb5_timestamp start_time) ++{ ++ G_LOCK (identity_lock); ++ if (self->priv->start_time != start_time) ++ { ++ self->priv->start_time = start_time; ++ G_UNLOCK (identity_lock); ++ queue_notify (self, ++ &self->priv->start_time_idle_id, ++ "start-timestamp"); ++ G_LOCK (identity_lock); ++ } ++ G_UNLOCK (identity_lock); ++} ++ ++static void + set_expiration_time (GoaKerberosIdentity *self, + krb5_timestamp expiration_time) + { + G_LOCK (identity_lock); + if (self->priv->expiration_time != expiration_time) + { + self->priv->expiration_time = expiration_time; + G_UNLOCK (identity_lock); + queue_notify (self, + &self->priv->expiration_time_idle_id, + "expiration-timestamp"); + G_LOCK (identity_lock); + } + G_UNLOCK (identity_lock); + } + + static gboolean + credentials_are_expired (GoaKerberosIdentity *self, + krb5_creds *credentials, ++ krb5_timestamp *start_time, + krb5_timestamp *expiration_time) + { + krb5_timestamp current_time; + + current_time = get_current_time (self); + + G_LOCK (identity_lock); ++ if (self->priv->start_time == 0) ++ *start_time = credentials->times.starttime; ++ else ++ *start_time = MIN (self->priv->start_time, ++ credentials->times.starttime); + *expiration_time = MAX (credentials->times.endtime, + self->priv->expiration_time); + G_UNLOCK (identity_lock); + +- if (credentials->times.endtime <= current_time) ++ if (current_time < credentials->times.starttime || ++ credentials->times.endtime <= current_time) + { + return TRUE; + } + + return FALSE; + } + + static VerificationLevel + verify_identity (GoaKerberosIdentity *self, + char **preauth_identity_source, + GError **error) + { + krb5_principal principal = NULL; + krb5_cc_cursor cursor; + krb5_creds credentials; + krb5_error_code error_code; ++ krb5_timestamp start_time = 0; + krb5_timestamp expiration_time = 0; + VerificationLevel verification_level = VERIFICATION_LEVEL_UNVERIFIED; + + if (self->priv->credentials_cache == NULL) + goto out; + + error_code = krb5_cc_get_principal (self->priv->kerberos_context, + self->priv->credentials_cache, + &principal); + + if (error_code != 0) + { + if (error_code == KRB5_CC_END || error_code == KRB5_FCC_NOFILE) + goto out; + + set_error_from_krb5_error_code (self, + error, + GOA_IDENTITY_ERROR_NOT_FOUND, + error_code, + _("Could not find identity in " + "credential cache: %k")); + verification_level = VERIFICATION_LEVEL_ERROR; + goto out; + } + + error_code = krb5_cc_start_seq_get (self->priv->kerberos_context, + self->priv->credentials_cache, &cursor); + if (error_code != 0) + { + set_error_from_krb5_error_code (self, + error, + GOA_IDENTITY_ERROR_CREDENTIALS_UNAVAILABLE, + error_code, + _("Could not find identity " + "credentials in cache: %k")); + + verification_level = VERIFICATION_LEVEL_ERROR; + goto out; + } + + verification_level = VERIFICATION_LEVEL_UNVERIFIED; + + error_code = krb5_cc_next_cred (self->priv->kerberos_context, + self->priv->credentials_cache, + &cursor, + &credentials); + + while (error_code == 0) + { + if (credentials_validate_existence (self, principal, &credentials)) + { +- if (!credentials_are_expired (self, &credentials, &expiration_time)) ++ if (!credentials_are_expired (self, &credentials, &start_time, &expiration_time)) + verification_level = VERIFICATION_LEVEL_SIGNED_IN; + else + verification_level = VERIFICATION_LEVEL_EXISTS; + } + else + { + snoop_preauth_identity_from_credentials (self, &credentials, preauth_identity_source); + } + + krb5_free_cred_contents (self->priv->kerberos_context, &credentials); + + error_code = krb5_cc_next_cred (self->priv->kerberos_context, + self->priv->credentials_cache, + &cursor, + &credentials); + } + + if (error_code != KRB5_CC_END) + { + verification_level = VERIFICATION_LEVEL_ERROR; + + set_error_from_krb5_error_code (self, + error, + GOA_IDENTITY_ERROR_ENUMERATING_CREDENTIALS, + error_code, + _("Could not sift through identity " + "credentials in cache: %k")); + goto end_sequence; + } + + end_sequence: + error_code = krb5_cc_end_seq_get (self->priv->kerberos_context, + self->priv->credentials_cache, + &cursor); + + if (error_code != 0) + { + verification_level = VERIFICATION_LEVEL_ERROR; + + set_error_from_krb5_error_code (self, + error, + GOA_IDENTITY_ERROR_ENUMERATING_CREDENTIALS, + error_code, + _("Could not finish up sifting through " + "identity credentials in cache: %k")); + goto out; + } + out: ++ set_start_time (self, start_time); + set_expiration_time (self, expiration_time); + + if (principal != NULL) + krb5_free_principal (self->priv->kerberos_context, principal); + return verification_level; + } + + static gboolean + goa_kerberos_identity_is_signed_in (GoaIdentity *identity) + { + GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (identity); + gboolean is_signed_in = FALSE; + + G_LOCK (identity_lock); + if (self->priv->cached_verification_level == VERIFICATION_LEVEL_SIGNED_IN) + is_signed_in = TRUE; + G_UNLOCK (identity_lock); + + return is_signed_in; + } + + static void + identity_interface_init (GoaIdentityInterface *interface) + { + interface->get_identifier = goa_kerberos_identity_get_identifier; + interface->is_signed_in = goa_kerberos_identity_is_signed_in; + } + + static void + on_expiration_alarm_fired (GoaAlarm *alarm, +@@ -895,90 +932,90 @@ connect_alarm_signals (GoaKerberosIdentity *self) + { + g_signal_connect (G_OBJECT (self->priv->renewal_alarm), + "fired", + G_CALLBACK (on_renewal_alarm_fired), + self); + g_signal_connect (G_OBJECT (self->priv->renewal_alarm), + "rearmed", + G_CALLBACK (on_renewal_alarm_rearmed), + self); + g_signal_connect (G_OBJECT (self->priv->expiring_alarm), + "fired", + G_CALLBACK (on_expiring_alarm_fired), + self); + g_signal_connect (G_OBJECT (self->priv->expiring_alarm), + "rearmed", + G_CALLBACK (on_expiring_alarm_rearmed), + self); + g_signal_connect (G_OBJECT (self->priv->expiration_alarm), + "fired", + G_CALLBACK (on_expiration_alarm_fired), + self); + g_signal_connect (G_OBJECT (self->priv->expiration_alarm), + "rearmed", + G_CALLBACK (on_expiration_alarm_rearmed), + self); + } + + static void + reset_alarms (GoaKerberosIdentity *self) + { +- GDateTime *now; ++ GDateTime *start_time; + GDateTime *expiration_time; + GDateTime *expiring_time; + GDateTime *renewal_time; +- GTimeSpan time_span_until_expiration; ++ GTimeSpan lifespan; + +- now = g_date_time_new_now_local (); + G_LOCK (identity_lock); ++ start_time = g_date_time_new_from_unix_local (self->priv->start_time); + expiration_time = g_date_time_new_from_unix_local (self->priv->expiration_time); + G_UNLOCK (identity_lock); +- time_span_until_expiration = g_date_time_difference (expiration_time, now); +- g_date_time_unref (now); ++ ++ lifespan = g_date_time_difference (expiration_time, start_time); + + /* Let the user reauthenticate 10 min before expiration */ + expiring_time = g_date_time_add_minutes (expiration_time, -10); + + /* Try to quietly auto-renew halfway through so in ideal configurations + * the ticket is never more than halfway to expired + */ +- renewal_time = g_date_time_add (expiration_time, +- -(time_span_until_expiration / 2)); ++ renewal_time = g_date_time_add (expiration_time, -(lifespan / 2)); + + disconnect_alarm_signals (self); + + reset_alarm (self, &self->priv->renewal_alarm, renewal_time); + reset_alarm (self, &self->priv->expiring_alarm, expiring_time); + reset_alarm (self, &self->priv->expiration_alarm, expiration_time); + + g_date_time_unref (renewal_time); + g_date_time_unref (expiring_time); ++ g_date_time_unref (start_time); + g_date_time_unref (expiration_time); + connect_alarm_signals (self); + } + + static void + clear_alarms (GoaKerberosIdentity *self) + { + disconnect_alarm_signals (self); + clear_alarm_and_unref_on_idle (self, &self->priv->renewal_alarm); + clear_alarm_and_unref_on_idle (self, &self->priv->expiring_alarm); + clear_alarm_and_unref_on_idle (self, &self->priv->expiration_alarm); + } + + static gboolean + goa_kerberos_identity_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) + { + GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (initable); + GError *verification_error; + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return FALSE; + + if (self->priv->identifier == NULL) + { + self->priv->identifier = get_identifier (self, error); + + if (self->priv->identifier != NULL) + queue_notify (self, &self->priv->identifier_idle_id, "identifier"); +-- +2.5.0 + + +From 57757628e01dcd1d6ce9855bdad70d5f69757157 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Tue, 22 Sep 2015 14:41:05 -0400 +Subject: [PATCH 2/3] identity: don't ever nullify identifier + +credentials stored in the kernel keyring disappear after they expire. +This is is different from other credential caches, which hang around +but maintain an expired timestamp until kdestroy. Because the credentials +vanish, trying to read the principal from an previously existing credential +cache, will yield NULL. + +This can lead to a crash in goa which never expects the identifier of an +identity object to be NULL. + +This commit makes sure we retain the old identifier in the event the +credential cache gets wiped. +--- + src/goaidentity/goakerberosidentity.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/goaidentity/goakerberosidentity.c b/src/goaidentity/goakerberosidentity.c +index 6865535..f43978d 100644 +--- a/src/goaidentity/goakerberosidentity.c ++++ b/src/goaidentity/goakerberosidentity.c +@@ -1355,61 +1355,61 @@ goa_kerberos_identity_sign_in (GoaKerberosIdentity *self, + goto done; + } + + if (destroy_notify) + destroy_notify (inquiry_data); + sign_in_operation_free (operation); + + if (!goa_kerberos_identity_update_credentials (self, + principal, + &new_credentials, + error)) + { + krb5_free_principal (self->priv->kerberos_context, principal); + goto done; + } + krb5_free_principal (self->priv->kerberos_context, principal); + + g_debug ("GoaKerberosIdentity: identity signed in"); + signed_in = TRUE; + done: + + return signed_in; + } + + static void + update_identifier (GoaKerberosIdentity *self, GoaKerberosIdentity *new_identity) + { + char *new_identifier; + + new_identifier = get_identifier (self, NULL); +- if (g_strcmp0 (self->priv->identifier, new_identifier) != 0) ++ if (g_strcmp0 (self->priv->identifier, new_identifier) != 0 && new_identifier != NULL) + { + g_free (self->priv->identifier); + self->priv->identifier = new_identifier; + queue_notify (self, &self->priv->identifier_idle_id, "identifier"); + } + else + { + g_free (new_identifier); + } + } + + void + goa_kerberos_identity_update (GoaKerberosIdentity *self, + GoaKerberosIdentity *new_identity) + { + VerificationLevel verification_level; + char *preauth_identity_source = NULL; + + if (self->priv->credentials_cache != NULL) + krb5_cc_close (self->priv->kerberos_context, self->priv->credentials_cache); + + krb5_cc_dup (new_identity->priv->kerberos_context, + new_identity->priv->credentials_cache, + &self->priv->credentials_cache); + + G_LOCK (identity_lock); + update_identifier (self, new_identity); + G_UNLOCK (identity_lock); + + verification_level = verify_identity (self, &preauth_identity_source, NULL); +-- +2.5.0 + + +From 8d8a923530402fef8dd04b5b4efd349c45118e13 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Tue, 22 Sep 2015 14:38:29 -0400 +Subject: [PATCH 3/3] identity: don't ignore almost all renewal requests + +There's a bug in the code where we ignore all renewal requests for +objects we already know about. + +This means we'll only ever honor renewal requests that happen almost +immediately after start up. + +This commit fixes the bug, so the only renewal requests that aren't +honored, are those that have been specifically disabled by the user. +This was clearly the original intention of the buggy code. +--- + src/goaidentity/goaidentityservice.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/src/goaidentity/goaidentityservice.c b/src/goaidentity/goaidentityservice.c +index 6b6225a..bb5d3a7 100644 +--- a/src/goaidentity/goaidentityservice.c ++++ b/src/goaidentity/goaidentityservice.c +@@ -714,70 +714,71 @@ static void + on_identity_renewed (GoaIdentityManager *manager, + GAsyncResult *result, + GoaIdentityService *self) + { + GError *error; + + error = NULL; + goa_identity_manager_renew_identity_finish (manager, result, &error); + + if (error != NULL) + { + g_debug ("GoaIdentityService: could not renew identity: %s", + error->message); + g_error_free (error); + return; + } + + g_debug ("GoaIdentityService: identity renewed"); + } + + static void + on_identity_needs_renewal (GoaIdentityManager *identity_manager, + GoaIdentity *identity, + GoaIdentityService *self) + { + const char *principal; + GoaObject *object; + + principal = goa_identity_get_identifier (identity); + +- g_debug ("GoaIdentityService: identity %s needs renewal", principal); +- + object = find_object_with_principal (self, principal, TRUE); + +- if (object != NULL) ++ if (object != NULL && should_ignore_object (self, object)) + { +- should_ignore_object (self, object); ++ g_debug ("GoaIdentityService: ignoring identity %s that says it needs renewal", principal); ++ + return; + } + ++ g_debug ("GoaIdentityService: identity %s needs renewal", principal); ++ + goa_identity_manager_renew_identity (GOA_IDENTITY_MANAGER + (self->priv->identity_manager), + identity, + NULL, + (GAsyncReadyCallback) + on_identity_renewed, + self); + } + + static void + on_identity_signed_in (GoaIdentityManager *manager, + GAsyncResult *result, + GSimpleAsyncResult *operation_result) + { + GError *error; + GoaIdentity *identity; + + error = NULL; + identity = goa_identity_manager_sign_identity_in_finish (manager, result, &error); + + if (error != NULL) + { + g_debug ("GoaIdentityService: could not sign in identity: %s", + error->message); + g_simple_async_result_take_error (operation_result, error); + } + else + { + g_simple_async_result_set_op_res_gpointer (operation_result, + g_object_ref (identity), +-- +2.5.0 + diff --git a/SOURCES/kerberos-fixes.patch b/SOURCES/kerberos-fixes.patch deleted file mode 100644 index e73caed..0000000 --- a/SOURCES/kerberos-fixes.patch +++ /dev/null @@ -1,4663 +0,0 @@ -From 0c9359604da3091c53a152cebe0e21861d2fceee Mon Sep 17 00:00:00 2001 -From: Debarshi Ray -Date: Mon, 17 Mar 2014 09:20:49 -0400 -Subject: [PATCH 01/24] kerberos: fix leak in register_error_domain - -In the event a type was not known, we were leaking the -type name. - -https://bugzilla.gnome.org/show_bug.cgi?id=726353 ---- - src/goaidentity/goaidentityutils.c | 9 ++++++--- - 1 file changed, 6 insertions(+), 3 deletions(-) - -diff --git a/src/goaidentity/goaidentityutils.c b/src/goaidentity/goaidentityutils.c -index 2730664..064c3f6 100644 ---- a/src/goaidentity/goaidentityutils.c -+++ b/src/goaidentity/goaidentityutils.c -@@ -152,67 +152,70 @@ dashed_string_to_dbus_error_string (const char *dashed_string, - g_strdup_printf ("%s.%s.%s", new_prefix, dashed_string, studly_suffix); - g_free (studly_suffix); - i += strlen (new_prefix) + 1; - - dbus_error_string_length = strlen (dbus_error_string); - - dbus_error_string[i] = g_ascii_toupper (dbus_error_string[i]); - i++; - - while (i < dbus_error_string_length) - { - if (dbus_error_string[i] == '_' || dbus_error_string[i] == '-') - { - dbus_error_string[i] = '.'; - - if (g_ascii_isalpha (dbus_error_string[i + 1])) - dbus_error_string[i + 1] = g_ascii_toupper (dbus_error_string[i + 1]); - } - - i++; - } - - return dbus_error_string; - } - - void - goa_identity_utils_register_error_domain (GQuark error_domain, - GType error_enum) - { - const char *error_domain_string; -- char *type_name; -+ char *type_name = NULL; - GType type; - GTypeClass *type_class; - GEnumClass *enum_class; - guint i; - - error_domain_string = g_quark_to_string (error_domain); - type_name = dashed_string_to_studly_caps (error_domain_string); - type = g_type_from_name (type_name); - type_class = g_type_class_ref (type); - - if (type_class == NULL) - { -- goa_warning ("GoaIdentityUtils: Could not identity type %s", type_name); -- return; -+ g_warning ("GoaIdentityUtils: Could not identity type %s", type_name); -+ goto out; - } - - enum_class = G_ENUM_CLASS (type_class); - - for (i = 0; i < enum_class->n_values; i++) - { - char *dbus_error_string; - - dbus_error_string = dashed_string_to_dbus_error_string (error_domain_string, - "goa", - "org.gnome", - enum_class->values[i]. - value_nick); - - goa_debug ("GoaIdentityUtils: Registering dbus error %s", dbus_error_string); - g_dbus_error_register_error (error_domain, - enum_class->values[i].value, dbus_error_string); - g_free (dbus_error_string); - } - - g_type_class_unref (type_class); -+ -+ out: -+ g_free (type_name); - } --- -1.8.3.1 - - -From 74834f7fa69b8f5ad66008ad93029f8100fd28ee Mon Sep 17 00:00:00 2001 -From: Debarshi Ray -Date: Mon, 17 Mar 2014 09:26:03 -0400 -Subject: [PATCH 02/24] kerberos: refactor register_error_domain - -This commit move type class freeing to the -otherside of the "out" label to make the code -robust against potential future changes. - -https://bugzilla.gnome.org/show_bug.cgi?id=726353 ---- - src/goaidentity/goaidentityutils.c | 5 ++--- - 1 file changed, 2 insertions(+), 3 deletions(-) - -diff --git a/src/goaidentity/goaidentityutils.c b/src/goaidentity/goaidentityutils.c -index 064c3f6..9206099 100644 ---- a/src/goaidentity/goaidentityutils.c -+++ b/src/goaidentity/goaidentityutils.c -@@ -154,68 +154,67 @@ dashed_string_to_dbus_error_string (const char *dashed_string, - i += strlen (new_prefix) + 1; - - dbus_error_string_length = strlen (dbus_error_string); - - dbus_error_string[i] = g_ascii_toupper (dbus_error_string[i]); - i++; - - while (i < dbus_error_string_length) - { - if (dbus_error_string[i] == '_' || dbus_error_string[i] == '-') - { - dbus_error_string[i] = '.'; - - if (g_ascii_isalpha (dbus_error_string[i + 1])) - dbus_error_string[i + 1] = g_ascii_toupper (dbus_error_string[i + 1]); - } - - i++; - } - - return dbus_error_string; - } - - void - goa_identity_utils_register_error_domain (GQuark error_domain, - GType error_enum) - { - const char *error_domain_string; - char *type_name = NULL; - GType type; -- GTypeClass *type_class; -+ GTypeClass *type_class = NULL; - GEnumClass *enum_class; - guint i; - - error_domain_string = g_quark_to_string (error_domain); - type_name = dashed_string_to_studly_caps (error_domain_string); - type = g_type_from_name (type_name); - type_class = g_type_class_ref (type); - - if (type_class == NULL) - { - g_warning ("GoaIdentityUtils: Could not identity type %s", type_name); - goto out; - } - - enum_class = G_ENUM_CLASS (type_class); - - for (i = 0; i < enum_class->n_values; i++) - { - char *dbus_error_string; - - dbus_error_string = dashed_string_to_dbus_error_string (error_domain_string, - "goa", - "org.gnome", - enum_class->values[i]. - value_nick); - - goa_debug ("GoaIdentityUtils: Registering dbus error %s", dbus_error_string); - g_dbus_error_register_error (error_domain, - enum_class->values[i].value, dbus_error_string); - g_free (dbus_error_string); - } - -- g_type_class_unref (type_class); -- - out: -+ g_clear_pointer (&type_class, g_type_class_unref); - g_free (type_name); - } --- -1.8.3.1 - - -From 8cc66523fe300f96cd4b34e4ad16c99e9ed86731 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Mon, 17 Mar 2014 09:59:12 -0400 -Subject: [PATCH 03/24] kerberos: make enum_class in register_error_domain - const - -Just as a defensive programming measure. - -https://bugzilla.gnome.org/show_bug.cgi?id=726353 ---- - src/goaidentity/goaidentityutils.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/goaidentity/goaidentityutils.c b/src/goaidentity/goaidentityutils.c -index 9206099..abc8e2d 100644 ---- a/src/goaidentity/goaidentityutils.c -+++ b/src/goaidentity/goaidentityutils.c -@@ -155,61 +155,61 @@ dashed_string_to_dbus_error_string (const char *dashed_string, - - dbus_error_string_length = strlen (dbus_error_string); - - dbus_error_string[i] = g_ascii_toupper (dbus_error_string[i]); - i++; - - while (i < dbus_error_string_length) - { - if (dbus_error_string[i] == '_' || dbus_error_string[i] == '-') - { - dbus_error_string[i] = '.'; - - if (g_ascii_isalpha (dbus_error_string[i + 1])) - dbus_error_string[i + 1] = g_ascii_toupper (dbus_error_string[i + 1]); - } - - i++; - } - - return dbus_error_string; - } - - void - goa_identity_utils_register_error_domain (GQuark error_domain, - GType error_enum) - { - const char *error_domain_string; - char *type_name = NULL; - GType type; - GTypeClass *type_class = NULL; -- GEnumClass *enum_class; -+ const GEnumClass *enum_class; - guint i; - - error_domain_string = g_quark_to_string (error_domain); - type_name = dashed_string_to_studly_caps (error_domain_string); - type = g_type_from_name (type_name); - type_class = g_type_class_ref (type); - - if (type_class == NULL) - { - g_warning ("GoaIdentityUtils: Could not identity type %s", type_name); - goto out; - } - - enum_class = G_ENUM_CLASS (type_class); - - for (i = 0; i < enum_class->n_values; i++) - { - char *dbus_error_string; - - dbus_error_string = dashed_string_to_dbus_error_string (error_domain_string, - "goa", - "org.gnome", - enum_class->values[i]. - value_nick); - - goa_debug ("GoaIdentityUtils: Registering dbus error %s", dbus_error_string); - g_dbus_error_register_error (error_domain, - enum_class->values[i].value, dbus_error_string); - g_free (dbus_error_string); - } --- -1.8.3.1 - - -From e63005c61f4307a279863bde168b793d2840c575 Mon Sep 17 00:00:00 2001 -From: Debarshi Ray -Date: Mon, 17 Mar 2014 09:28:32 -0400 -Subject: [PATCH 04/24] kerberos: fix leak in add_temporary_account - -The account description was not getting freed. - -https://bugzilla.gnome.org/show_bug.cgi?id=726353 ---- - src/goaidentity/goaidentityservice.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/goaidentity/goaidentityservice.c b/src/goaidentity/goaidentityservice.c -index 1639868..83b40af 100644 ---- a/src/goaidentity/goaidentityservice.c -+++ b/src/goaidentity/goaidentityservice.c -@@ -850,116 +850,117 @@ on_account_added (GoaManager *manager, - } - - if (object_path != NULL && object_path[0] != '\0') - { - goa_debug ("Created account for identity with object path %s", object_path); - - object_manager = goa_client_get_object_manager (self->priv->client); - object = GOA_OBJECT (g_dbus_object_manager_get_object (object_manager, - object_path)); - g_free (object_path); - } - - if (object == NULL) - g_simple_async_result_set_op_res_gpointer (operation_result, NULL, NULL); - else - g_simple_async_result_set_op_res_gpointer (operation_result, - object, - (GDestroyNotify) - g_object_unref); - - g_simple_async_result_complete_in_idle (operation_result); - g_object_unref (operation_result); - } - - static void - add_temporary_account (GoaIdentityService *self, - GoaIdentity *identity) - { - char *realm; - const char *principal; -- const char *principal_for_display; -+ char *principal_for_display; - GSimpleAsyncResult *operation_result; - GVariantBuilder credentials; - GVariantBuilder details; - GoaObject *object; - - principal = goa_identity_get_identifier (identity); - - object = g_hash_table_lookup (self->priv->pending_temporary_account_results, - principal); - - if (object != NULL) - { - goa_debug ("GoaIdentityService: would add temporary identity %s, but it's already pending", principal); - return; - } - - goa_debug ("GoaIdentityService: adding temporary identity %s", principal); - - /* If there's no account for this identity then create a temporary one. - */ - principal_for_display = goa_identity_manager_name_identity (self->priv->identity_manager, - identity); - - realm = goa_kerberos_identity_get_realm_name (GOA_KERBEROS_IDENTITY (identity)); - - g_variant_builder_init (&credentials, G_VARIANT_TYPE_VARDICT); - - g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}")); - g_variant_builder_add (&details, "{ss}", "Realm", realm); - g_variant_builder_add (&details, "{ss}", "IsTemporary", "true"); - g_variant_builder_add (&details, "{ss}", "TicketingEnabled", "true"); - - - goa_debug ("GoaIdentityService: asking to sign back in"); - - operation_result = g_simple_async_result_new (G_OBJECT (self), - (GAsyncReadyCallback) - on_temporary_account_created_for_identity, - identity, - add_temporary_account); - g_hash_table_insert (self->priv->pending_temporary_account_results, - g_strdup (principal), - g_object_ref (operation_result)); - - goa_manager_call_add_account (self->priv->accounts_manager, - "kerberos", - principal, - principal_for_display, - g_variant_builder_end (&credentials), - g_variant_builder_end (&details), - NULL, - (GAsyncReadyCallback) - on_account_added, - operation_result); - g_free (realm); -+ g_free (principal_for_display); - } - - static void - on_identity_added (GoaIdentityManager *identity_manager, - GoaIdentity *identity, - GoaIdentityService *self) - { - GoaObject *object; - const char *identifier; - - export_identity (self, identity); - - identifier = goa_identity_get_identifier (identity); - - object = find_object_with_principal (self, identifier, FALSE); - - if (object == NULL) - add_temporary_account (self, identity); - } - - static void - on_identity_removed (GoaIdentityManager *identity_manager, - GoaIdentity *identity, - GoaIdentityService *self) - { - GoaObject *object; - const char *identifier; - - identifier = goa_identity_get_identifier (identity); - object = find_object_with_principal (self, identifier, FALSE); --- -1.8.3.1 - - -From f9f597f8df9b00bd2e42ce6177fa4505d2e8c3d9 Mon Sep 17 00:00:00 2001 -From: Michael Cronenworth -Date: Mon, 17 Mar 2014 09:33:59 -0400 -Subject: [PATCH 05/24] kerberos: don't free alarm in set_alarm, free in - callers - -It's a little unexpected that set_alarm "eats" the alarm passed in. -This commit makes it the caller's responsibility to free the alarm -to more closely match typical practice. - -https://bugzilla.gnome.org/show_bug.cgi?id=726353 ---- - src/goaidentity/goakerberosidentity.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/src/goaidentity/goakerberosidentity.c b/src/goaidentity/goakerberosidentity.c -index 048f36b..2c1cdf7 100644 ---- a/src/goaidentity/goakerberosidentity.c -+++ b/src/goaidentity/goakerberosidentity.c -@@ -760,61 +760,60 @@ on_expiring_alarm_fired (GoaAlarm *alarm, - GoaKerberosIdentity *self) - { - g_return_if_fail (GOA_IS_ALARM (alarm)); - g_return_if_fail (GOA_IS_KERBEROS_IDENTITY (self)); - - g_clear_object (&self->priv->expiring_alarm_cancellable); - - if (self->priv->cached_verification_level == VERIFICATION_LEVEL_SIGNED_IN) - { - goa_debug ("GoaKerberosIdentity: expiring alarm fired for signed-in identity"); - g_signal_emit (G_OBJECT (self), signals[EXPIRING], 0); - } - } - - static void - set_alarm (GoaKerberosIdentity *self, - GoaAlarm *alarm, - GDateTime *alarm_time, - GCancellable **cancellable) - { - GDateTime *old_alarm_time; - - G_LOCK (identity_lock); - old_alarm_time = goa_alarm_get_time (alarm); - if (old_alarm_time == NULL || !g_date_time_equal (alarm_time, old_alarm_time)) - { - GCancellable *new_cancellable; - - new_cancellable = g_cancellable_new (); - goa_alarm_set_time (alarm, alarm_time, new_cancellable); -- g_date_time_unref (alarm_time); - - g_clear_object (cancellable); - *cancellable = new_cancellable; - } - G_UNLOCK (identity_lock); - - } - - static void - disconnect_alarm_signals (GoaKerberosIdentity *self) - { - g_signal_handlers_disconnect_by_func (G_OBJECT (self->priv->renewal_alarm), - G_CALLBACK (on_renewal_alarm_fired), - self); - g_signal_handlers_disconnect_by_func (G_OBJECT (self->priv->renewal_alarm), - G_CALLBACK (on_renewal_alarm_rearmed), - self); - g_signal_handlers_disconnect_by_func (G_OBJECT (self->priv->expiring_alarm), - G_CALLBACK (on_expiring_alarm_fired), - self); - g_signal_handlers_disconnect_by_func (G_OBJECT (self->priv->expiration_alarm), - G_CALLBACK (on_expiration_alarm_rearmed), - self); - g_signal_handlers_disconnect_by_func (G_OBJECT (self->priv->expiration_alarm), - G_CALLBACK (on_expiration_alarm_fired), - self); - g_signal_handlers_disconnect_by_func (G_OBJECT (self->priv->expiring_alarm), - G_CALLBACK (on_expiring_alarm_rearmed), - self); - } -@@ -855,60 +854,63 @@ reset_alarms (GoaKerberosIdentity *self) - GDateTime *expiration_time; - GDateTime *expiring_time; - GDateTime *renewal_time; - GTimeSpan time_span_until_expiration; - - now = g_date_time_new_now_local (); - expiration_time = g_date_time_new_from_unix_local (self->priv->expiration_time); - time_span_until_expiration = g_date_time_difference (expiration_time, now); - - /* Let the user reauthenticate 10 min before expiration */ - expiring_time = g_date_time_add_minutes (expiration_time, -10); - - /* Try to quietly auto-renew halfway through so in ideal configurations - * the ticket is never more than halfway to expired - */ - renewal_time = g_date_time_add (expiration_time, - -(time_span_until_expiration / 2)); - - disconnect_alarm_signals (self); - - set_alarm (self, - self->priv->renewal_alarm, - renewal_time, &self->priv->renewal_alarm_cancellable); - set_alarm (self, - self->priv->expiring_alarm, - expiring_time, &self->priv->expiring_alarm_cancellable); - set_alarm (self, - self->priv->expiration_alarm, - expiration_time, &self->priv->expiration_alarm_cancellable); - -+ g_date_time_unref (renewal_time); -+ g_date_time_unref (expiring_time); -+ g_date_time_unref (expiration_time); - connect_alarm_signals (self); - } - - static void - cancel_and_clear_cancellable (GCancellable **cancellable) - { - if (cancellable == NULL) - return; - - if (!g_cancellable_is_cancelled (*cancellable)) - g_cancellable_cancel (*cancellable); - - g_clear_object (cancellable); - } - - static void - clear_alarms (GoaKerberosIdentity *self) - { - cancel_and_clear_cancellable (&self->priv->renewal_alarm_cancellable); - cancel_and_clear_cancellable (&self->priv->expiring_alarm_cancellable); - cancel_and_clear_cancellable (&self->priv->expiration_alarm_cancellable); - } - - static gboolean - goa_kerberos_identity_initable_init (GInitable *initable, - GCancellable *cancellable, - GError **error) - { - GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (initable); - GError *verification_error; --- -1.8.3.1 - - -From ef2b475703f482759d3b8af03d72ef8f04a53c84 Mon Sep 17 00:00:00 2001 -From: Michael Cronenworth -Date: Mon, 17 Mar 2014 09:33:59 -0400 -Subject: [PATCH 06/24] kerberos: fix leak in reset_alarms - -A GDateTime "now" object wasn't getting cleaned up after use. - -https://bugzilla.gnome.org/show_bug.cgi?id=726353 ---- - src/goaidentity/goakerberosidentity.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/goaidentity/goakerberosidentity.c b/src/goaidentity/goakerberosidentity.c -index 2c1cdf7..ddbad75 100644 ---- a/src/goaidentity/goakerberosidentity.c -+++ b/src/goaidentity/goakerberosidentity.c -@@ -832,60 +832,61 @@ connect_alarm_signals (GoaKerberosIdentity *self) - g_signal_connect (G_OBJECT (self->priv->expiring_alarm), - "fired", - G_CALLBACK (on_expiring_alarm_fired), - self); - g_signal_connect (G_OBJECT (self->priv->expiring_alarm), - "rearmed", - G_CALLBACK (on_expiring_alarm_rearmed), - self); - g_signal_connect (G_OBJECT (self->priv->expiration_alarm), - "fired", - G_CALLBACK (on_expiration_alarm_fired), - self); - g_signal_connect (G_OBJECT (self->priv->expiration_alarm), - "rearmed", - G_CALLBACK (on_expiration_alarm_rearmed), - self); - } - - static void - reset_alarms (GoaKerberosIdentity *self) - { - GDateTime *now; - GDateTime *expiration_time; - GDateTime *expiring_time; - GDateTime *renewal_time; - GTimeSpan time_span_until_expiration; - - now = g_date_time_new_now_local (); - expiration_time = g_date_time_new_from_unix_local (self->priv->expiration_time); - time_span_until_expiration = g_date_time_difference (expiration_time, now); -+ g_date_time_unref (now); - - /* Let the user reauthenticate 10 min before expiration */ - expiring_time = g_date_time_add_minutes (expiration_time, -10); - - /* Try to quietly auto-renew halfway through so in ideal configurations - * the ticket is never more than halfway to expired - */ - renewal_time = g_date_time_add (expiration_time, - -(time_span_until_expiration / 2)); - - disconnect_alarm_signals (self); - - set_alarm (self, - self->priv->renewal_alarm, - renewal_time, &self->priv->renewal_alarm_cancellable); - set_alarm (self, - self->priv->expiring_alarm, - expiring_time, &self->priv->expiring_alarm_cancellable); - set_alarm (self, - self->priv->expiration_alarm, - expiration_time, &self->priv->expiration_alarm_cancellable); - - g_date_time_unref (renewal_time); - g_date_time_unref (expiring_time); - g_date_time_unref (expiration_time); - connect_alarm_signals (self); - } - - static void - cancel_and_clear_cancellable (GCancellable **cancellable) --- -1.8.3.1 - - -From 226db9d5df98b9872b9930b0899d923bb4418f70 Mon Sep 17 00:00:00 2001 -From: Debarshi Ray -Date: Mon, 17 Mar 2014 09:42:13 -0400 -Subject: [PATCH 07/24] kerberos: fix principal leak in identity_renew - -The code carefully freed the principal in all error cases, but then -failed to free the principal in the non-error case! - -https://bugzilla.gnome.org/show_bug.cgi?id=726353 ---- - src/goaidentity/goakerberosidentity.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/src/goaidentity/goakerberosidentity.c b/src/goaidentity/goakerberosidentity.c -index ddbad75..d8c5c66 100644 ---- a/src/goaidentity/goakerberosidentity.c -+++ b/src/goaidentity/goakerberosidentity.c -@@ -1379,60 +1379,63 @@ goa_kerberos_identity_renew (GoaKerberosIdentity *self, GError **error) - name = goa_kerberos_identity_get_principal_name (self); - - error_code = krb5_get_renewed_creds (self->priv->kerberos_context, - &new_credentials, - principal, - self->priv->credentials_cache, NULL); - if (error_code != 0) - { - set_error_from_krb5_error_code (self, - error, - GOA_IDENTITY_ERROR_RENEWING, - error_code, - _ - ("Could not get new credentials to renew identity %s: %k"), - name); - krb5_free_principal (self->priv->kerberos_context, principal); - goto out; - } - - if (!goa_kerberos_identity_update_credentials (self, - principal, - &new_credentials, - error)) - { - krb5_free_principal (self->priv->kerberos_context, principal); - goto out; - } - - goa_debug ("GoaKerberosIdentity: identity %s renewed", name); - renewed = TRUE; -+ -+ krb5_free_principal (self->priv->kerberos_context, principal); -+ - out: - g_free (name); - - return renewed; - } - - gboolean - goa_kerberos_identity_erase (GoaKerberosIdentity *self, GError **error) - { - krb5_error_code error_code = 0; - - if (self->priv->credentials_cache != NULL) - { - error_code = krb5_cc_destroy (self->priv->kerberos_context, - self->priv->credentials_cache); - self->priv->credentials_cache = NULL; - } - - if (error_code != 0) - { - set_error_from_krb5_error_code (self, - error, - GOA_IDENTITY_ERROR_REMOVING_CREDENTIALS, - error_code, _("Could not erase identity: %k")); - return FALSE; - } - - return TRUE; - } - --- -1.8.3.1 - - -From 30d997961fe88b02a9405219563c5d7df13f99ab Mon Sep 17 00:00:00 2001 -From: Debarshi Ray -Date: Mon, 17 Mar 2014 09:44:05 -0400 -Subject: [PATCH 08/24] kerberos: consolidate exit path code in identity_renew - -the principal is freed in 3 different places. This commit -consolidates it to one place for clarity and added robustness -against future changes. - -https://bugzilla.gnome.org/show_bug.cgi?id=726353 ---- - src/goaidentity/goakerberosidentity.c | 7 +++---- - 1 file changed, 3 insertions(+), 4 deletions(-) - -diff --git a/src/goaidentity/goakerberosidentity.c b/src/goaidentity/goakerberosidentity.c -index d8c5c66..200c74b 100644 ---- a/src/goaidentity/goakerberosidentity.c -+++ b/src/goaidentity/goakerberosidentity.c -@@ -1364,76 +1364,75 @@ goa_kerberos_identity_renew (GoaKerberosIdentity *self, GError **error) - goto out; - } - - error_code = krb5_cc_get_principal (self->priv->kerberos_context, - self->priv->credentials_cache, &principal); - - if (error_code != 0) - { - set_error_from_krb5_error_code (self, - error, - GOA_IDENTITY_ERROR_CREDENTIALS_UNAVAILABLE, - error_code, _("Could not renew identity: %k")); - goto out; - } - - name = goa_kerberos_identity_get_principal_name (self); - - error_code = krb5_get_renewed_creds (self->priv->kerberos_context, - &new_credentials, - principal, - self->priv->credentials_cache, NULL); - if (error_code != 0) - { - set_error_from_krb5_error_code (self, - error, - GOA_IDENTITY_ERROR_RENEWING, - error_code, - _ - ("Could not get new credentials to renew identity %s: %k"), - name); -- krb5_free_principal (self->priv->kerberos_context, principal); -- goto out; -+ goto free_principal; - } - - if (!goa_kerberos_identity_update_credentials (self, - principal, - &new_credentials, - error)) - { -- krb5_free_principal (self->priv->kerberos_context, principal); -- goto out; -+ goto free_principal; - } - - goa_debug ("GoaKerberosIdentity: identity %s renewed", name); - renewed = TRUE; - -+free_principal: - krb5_free_principal (self->priv->kerberos_context, principal); - - out: - g_free (name); - - return renewed; - } - - gboolean - goa_kerberos_identity_erase (GoaKerberosIdentity *self, GError **error) - { - krb5_error_code error_code = 0; - - if (self->priv->credentials_cache != NULL) - { - error_code = krb5_cc_destroy (self->priv->kerberos_context, - self->priv->credentials_cache); - self->priv->credentials_cache = NULL; - } - - if (error_code != 0) - { - set_error_from_krb5_error_code (self, - error, - GOA_IDENTITY_ERROR_REMOVING_CREDENTIALS, - error_code, _("Could not erase identity: %k")); - return FALSE; - } - - return TRUE; --- -1.8.3.1 - - -From 2a599702c690712a0b1fd6b04d59b8d5b21a8548 Mon Sep 17 00:00:00 2001 -From: Michael Cronenworth -Date: Mon, 17 Mar 2014 09:47:01 -0400 -Subject: [PATCH 09/24] kerberos: fix leak in verify_identity - -The kerberos API allocates credentials on the heap, when iterating -over a credential collection (for each iteration). - -This commit makes sure each of those credentials is freed. - -https://bugzilla.gnome.org/show_bug.cgi?id=726353 ---- - src/goaidentity/goakerberosidentity.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/src/goaidentity/goakerberosidentity.c b/src/goaidentity/goakerberosidentity.c -index 200c74b..15a719d 100644 ---- a/src/goaidentity/goakerberosidentity.c -+++ b/src/goaidentity/goakerberosidentity.c -@@ -608,60 +608,62 @@ verify_identity (GoaKerberosIdentity *self, - if (error_code != 0) - { - set_error_from_krb5_error_code (self, - error, - GOA_IDENTITY_ERROR_CREDENTIALS_UNAVAILABLE, - error_code, - _("Could not find identity " - "credentials in cache: %k")); - - verification_level = VERIFICATION_LEVEL_ERROR; - goto out; - } - - verification_level = VERIFICATION_LEVEL_UNVERIFIED; - - error_code = krb5_cc_next_cred (self->priv->kerberos_context, - self->priv->credentials_cache, - &cursor, - &credentials); - - while (error_code == 0) - { - if (credentials_validate_existence (self, principal, &credentials)) - { - if (!credentials_are_expired (self, &credentials)) - verification_level = VERIFICATION_LEVEL_SIGNED_IN; - else - verification_level = VERIFICATION_LEVEL_EXISTS; - } - -+ krb5_free_cred_contents (self->priv->kerberos_context, &credentials); -+ - error_code = krb5_cc_next_cred (self->priv->kerberos_context, - self->priv->credentials_cache, - &cursor, - &credentials); - } - - if (error_code != KRB5_CC_END) - { - verification_level = VERIFICATION_LEVEL_ERROR; - - set_error_from_krb5_error_code (self, - error, - GOA_IDENTITY_ERROR_ENUMERATING_CREDENTIALS, - error_code, - _("Could not sift through identity " - "credentials in cache: %k")); - goto out; - } - - error_code = krb5_cc_end_seq_get (self->priv->kerberos_context, - self->priv->credentials_cache, - &cursor); - - if (error_code != 0) - { - verification_level = VERIFICATION_LEVEL_ERROR; - - set_error_from_krb5_error_code (self, - error, - GOA_IDENTITY_ERROR_ENUMERATING_CREDENTIALS, --- -1.8.3.1 - - -From 4eeea6fa96c27148d47dd5d70c7448c551049aa8 Mon Sep 17 00:00:00 2001 -From: Debarshi Ray -Date: Mon, 17 Mar 2014 09:51:27 -0400 -Subject: [PATCH 10/24] kerberos: make sure credential cache sequence is always - explicitly ended - -The code currently fails to pair krb5_cc_start_seq_get with krb5_cc_end_seq_get -in an error case. This can lead the cursor getting leaked. - -https://bugzilla.gnome.org/show_bug.cgi?id=726353 ---- - src/goaidentity/goakerberosidentity.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/goaidentity/goakerberosidentity.c b/src/goaidentity/goakerberosidentity.c -index 15a719d..9308295 100644 ---- a/src/goaidentity/goakerberosidentity.c -+++ b/src/goaidentity/goakerberosidentity.c -@@ -626,63 +626,64 @@ verify_identity (GoaKerberosIdentity *self, - &credentials); - - while (error_code == 0) - { - if (credentials_validate_existence (self, principal, &credentials)) - { - if (!credentials_are_expired (self, &credentials)) - verification_level = VERIFICATION_LEVEL_SIGNED_IN; - else - verification_level = VERIFICATION_LEVEL_EXISTS; - } - - krb5_free_cred_contents (self->priv->kerberos_context, &credentials); - - error_code = krb5_cc_next_cred (self->priv->kerberos_context, - self->priv->credentials_cache, - &cursor, - &credentials); - } - - if (error_code != KRB5_CC_END) - { - verification_level = VERIFICATION_LEVEL_ERROR; - - set_error_from_krb5_error_code (self, - error, - GOA_IDENTITY_ERROR_ENUMERATING_CREDENTIALS, - error_code, - _("Could not sift through identity " - "credentials in cache: %k")); -- goto out; -+ goto end_sequence; - } - -+ end_sequence: - error_code = krb5_cc_end_seq_get (self->priv->kerberos_context, - self->priv->credentials_cache, - &cursor); - - if (error_code != 0) - { - verification_level = VERIFICATION_LEVEL_ERROR; - - set_error_from_krb5_error_code (self, - error, - GOA_IDENTITY_ERROR_ENUMERATING_CREDENTIALS, - error_code, - _("Could not finish up sifting through " - "identity credentials in cache: %k")); - goto out; - } - out: - krb5_free_principal (self->priv->kerberos_context, principal); - return verification_level; - } - - static gboolean - goa_kerberos_identity_is_signed_in (GoaIdentity *identity) - { - GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (identity); - gboolean is_signed_in = FALSE; - - G_LOCK (identity_lock); - if (self->priv->cached_verification_level == VERIFICATION_LEVEL_SIGNED_IN) - is_signed_in = TRUE; --- -1.8.3.1 - - -From cb0607ad1aa5eedeefa410a1297e240b43d1eaaa Mon Sep 17 00:00:00 2001 -From: Debarshi Ray -Date: Wed, 9 Apr 2014 14:44:46 +0200 -Subject: [PATCH 11/24] identity: Remove unused variables - -Fallout from f4c3d303bf7ecc9e0cc6288d787c118365c1d34a - -Fixes: https://bugzilla.gnome.org/686416 ---- - src/goaidentity/goaidentityservice.c | 9 --------- - 1 file changed, 9 deletions(-) - -diff --git a/src/goaidentity/goaidentityservice.c b/src/goaidentity/goaidentityservice.c -index 83b40af..3321b0f 100644 ---- a/src/goaidentity/goaidentityservice.c -+++ b/src/goaidentity/goaidentityservice.c -@@ -21,63 +21,60 @@ - */ - - #include "config.h" - #include "goaidentityservice.h" - - #include - #include - - #include - #include - #include - - #include - - #include - - #include "goaidentityenumtypes.h" - #include "goaidentityutils.h" - - #include "goakerberosidentitymanager.h" - #include "goalogging.h" - - struct _GoaIdentityServicePrivate - { - GDBusConnection *connection; - GDBusObjectManagerServer *object_manager_server; - guint bus_id; - - GoaIdentityManager *identity_manager; - -- guint realmd_watch; -- GCancellable *cancellable; -- - GHashTable *watched_client_connections; - GHashTable *key_holders; - GHashTable *pending_temporary_account_results; - - /* FIXME: This is a little ucky, since the goa service - * is in process, we should able to use direct calls. - */ - GoaClient *client; - GoaManager *accounts_manager; - }; - - static void identity_service_manager_interface_init (GoaIdentityServiceManagerIface *interface); - - static void - sign_in (GoaIdentityService *self, - const char *identifier, - gconstpointer initial_password, - GoaIdentitySignInFlags flags, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - - G_DEFINE_TYPE_WITH_CODE (GoaIdentityService, - goa_identity_service, - GOA_IDENTITY_SERVICE_TYPE_MANAGER_SKELETON, - G_IMPLEMENT_INTERFACE (GOA_IDENTITY_SERVICE_TYPE_MANAGER, - identity_service_manager_interface_init)); - - static char * - get_object_path_for_identity (GoaIdentityService *self, -@@ -1727,101 +1724,95 @@ on_session_bus_acquired (GDBusConnection *connection, - } - - static void - on_name_acquired (GDBusConnection *connection, - const char *name, - GoaIdentityService *self) - { - if (g_strcmp0 (name, "org.gnome.Identity") == 0) - goa_debug ("GoaIdentityService: Acquired name org.gnome.Identity"); - } - - static void - on_name_lost (GDBusConnection *connection, - const char *name, - GoaIdentityService *self) - { - if (g_strcmp0 (name, "org.gnome.Identity") == 0) - goa_debug ("GoaIdentityService: Lost name org.gnome.Identity"); - } - - gboolean - goa_identity_service_activate (GoaIdentityService *self, - GError **error) - { - GoaIdentityServiceObjectSkeleton *object; - - g_return_val_if_fail (GOA_IS_IDENTITY_SERVICE (self), FALSE); - - goa_debug ("GoaIdentityService: Activating identity service"); - -- self->priv->cancellable = g_cancellable_new (); -- - self->priv->object_manager_server = - g_dbus_object_manager_server_new ("/org/gnome/Identity"); - - object = goa_identity_service_object_skeleton_new ("/org/gnome/Identity/Manager"); - goa_identity_service_object_skeleton_set_manager (object, - GOA_IDENTITY_SERVICE_MANAGER (self)); - - g_dbus_object_manager_server_export (self->priv->object_manager_server, - G_DBUS_OBJECT_SKELETON (object)); - g_object_unref (object); - - self->priv->bus_id = g_bus_own_name (G_BUS_TYPE_SESSION, - "org.gnome.Identity", - G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | - G_BUS_NAME_OWNER_FLAGS_REPLACE, - (GBusAcquiredCallback) on_session_bus_acquired, - (GBusNameAcquiredCallback) on_name_acquired, - (GBusNameVanishedCallback) on_name_lost, - self, - NULL); - - return TRUE; - } - - void - goa_identity_service_deactivate (GoaIdentityService *self) - { - goa_debug ("GoaIdentityService: Deactivating identity service"); - -- if (self->priv->realmd_watch == 0) -- g_bus_unwatch_name (self->priv->realmd_watch); -- - if (self->priv->identity_manager != NULL) - { - g_signal_handlers_disconnect_by_func (self, on_identity_needs_renewal, self); - g_signal_handlers_disconnect_by_func (self, on_identity_expiring, self); - g_signal_handlers_disconnect_by_func (self, on_identity_expired, self); - g_clear_object (&self->priv->identity_manager); - } - - g_clear_object (&self->priv->object_manager_server); - g_clear_object (&self->priv->connection); - g_clear_object (&self->priv->client); -- g_clear_object (&self->priv->cancellable); - } - - static void - goa_identity_service_class_init (GoaIdentityServiceClass *service_class) - { - GObjectClass *object_class = G_OBJECT_CLASS (service_class); - - object_class->finalize = goa_identity_service_finalize; - - goa_identity_utils_register_error_domain (GOA_IDENTITY_ERROR, GOA_TYPE_IDENTITY_ERROR); - goa_identity_utils_register_error_domain (GOA_IDENTITY_MANAGER_ERROR, GOA_TYPE_IDENTITY_MANAGER_ERROR); - - g_type_class_add_private (service_class, sizeof (GoaIdentityServicePrivate)); - } - - GoaIdentityService * - goa_identity_service_new (void) - { - GObject *object; - - object = g_object_new (GOA_TYPE_IDENTITY_SERVICE, - NULL); - - return GOA_IDENTITY_SERVICE (object); - } --- -1.8.3.1 - - -From 068c67b1d75dbda1b75da4c3f4d1e330eb47e130 Mon Sep 17 00:00:00 2001 -From: Debarshi Ray -Date: Wed, 9 Apr 2014 15:25:33 +0200 -Subject: [PATCH 12/24] kerberos: Correctly set the error if object creation - failed - -The error is actually a GError **, and not a GError *. There is no need -to set it to NULL. - -Fixes: https://bugzilla.gnome.org/727896 ---- - src/goaidentity/goakerberosidentitymanager.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/src/goaidentity/goakerberosidentitymanager.c b/src/goaidentity/goakerberosidentitymanager.c -index f3664fe..5e33003 100644 ---- a/src/goaidentity/goakerberosidentitymanager.c -+++ b/src/goaidentity/goakerberosidentitymanager.c -@@ -1645,47 +1645,46 @@ goa_kerberos_identity_manager_finalize (GObject *object) - krb5_free_context (self->priv->kerberos_context); - - G_OBJECT_CLASS (goa_kerberos_identity_manager_parent_class)->finalize (object); - } - - static void - goa_kerberos_identity_manager_class_init (GoaKerberosIdentityManagerClass *klass) - { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = goa_kerberos_identity_manager_dispose; - object_class->finalize = goa_kerberos_identity_manager_finalize; - - g_type_class_add_private (klass, sizeof (GoaKerberosIdentityManagerPrivate)); - } - - GoaIdentityManager * - goa_kerberos_identity_manager_new (GCancellable * cancellable, GError ** error) - { - if (goa_kerberos_identity_manager_singleton == NULL) - { - GObject *object; - - object = g_object_new (GOA_TYPE_KERBEROS_IDENTITY_MANAGER, NULL); - - goa_kerberos_identity_manager_singleton = GOA_IDENTITY_MANAGER (object); - g_object_add_weak_pointer (object, - (gpointer *) & - goa_kerberos_identity_manager_singleton); - -- error = NULL; - if (!g_initable_init (G_INITABLE (object), cancellable, error)) - { - g_object_unref (object); - return NULL; - } - - } - else - { - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - return NULL; - g_object_ref (goa_kerberos_identity_manager_singleton); - } - - return goa_kerberos_identity_manager_singleton; - } --- -1.8.3.1 - - -From 013eec484076d88d818030d88cea485171981e89 Mon Sep 17 00:00:00 2001 -From: Debarshi Ray -Date: Wed, 9 Apr 2014 15:31:50 +0200 -Subject: [PATCH 13/24] identity: Keep a reference to self during async - operations - -If the IdentityService object is freed while it's getting the initial -list of identities shortly after start up (i.e., the service is -exiting shortly after starting), then there's a chance the callback -associated with the identity listing operation could be called after -the service is freed (which could lead to a crash). - -This commit addresses that problem by reffing the service object until -the list operation finishes, preventing it from getting freed -prematurely. - -Fixes: https://bugzilla.gnome.org/727896 ---- - src/goaidentity/goaidentityservice.c | 20 +++++++++++++------- - 1 file changed, 13 insertions(+), 7 deletions(-) - -diff --git a/src/goaidentity/goaidentityservice.c b/src/goaidentity/goaidentityservice.c -index 3321b0f..d51d6bd 100644 ---- a/src/goaidentity/goaidentityservice.c -+++ b/src/goaidentity/goaidentityservice.c -@@ -1571,80 +1571,83 @@ on_identities_listed (GoaIdentityManager *manager, - "identity-refreshed", - G_CALLBACK (on_identity_refreshed), - self); - g_signal_connect (G_OBJECT (self->priv->identity_manager), - "identity-needs-renewal", - G_CALLBACK (on_identity_needs_renewal), - self); - g_signal_connect (G_OBJECT (self->priv->identity_manager), - "identity-expiring", - G_CALLBACK (on_identity_expiring), - self); - g_signal_connect (G_OBJECT (self->priv->identity_manager), - "identity-expired", - G_CALLBACK (on_identity_expired), - self); - - g_signal_connect (G_OBJECT (self->priv->client), - "account-removed", - G_CALLBACK (on_account_removed), - self); - - identities = goa_identity_manager_list_identities_finish (manager, result, &error); - - if (identities == NULL) - { - if (error != NULL) - { - goa_warning ("Could not list identities: %s", error->message); - g_error_free (error); - } -- return; -+ goto out; - } - - for (node = identities; node != NULL; node = node->next) - { - GoaIdentity *identity = node->data; - const char *principal; - GoaObject *object; - - export_identity (self, identity); - - principal = goa_identity_get_identifier (identity); - - object = find_object_with_principal (self, principal, TRUE); - - if (object == NULL) - add_temporary_account (self, identity); - else - g_object_unref (object); - } -+ -+ out: -+ g_object_unref (self); - } - - static void - ensure_credentials_for_accounts (GoaIdentityService *self) - { - GDBusObjectManager *object_manager; - GList *accounts; - GList *node; - - object_manager = goa_client_get_object_manager (self->priv->client); - - g_signal_connect (G_OBJECT (object_manager), - "interface-added", - G_CALLBACK (on_account_interface_added), - self); - g_signal_connect (G_OBJECT (object_manager), - "interface-removed", - G_CALLBACK (on_account_interface_removed), - self); - - accounts = goa_client_get_accounts (self->priv->client); - - for (node = accounts; node != NULL; node = node->next) - { - GoaObject *object = GOA_OBJECT (node->data); - GoaAccount *account; - GoaTicketing *ticketing; - const char *provider_type; - - account = goa_object_peek_account (object); -@@ -1652,101 +1655,104 @@ ensure_credentials_for_accounts (GoaIdentityService *self) - if (account == NULL) - continue; - - provider_type = goa_account_get_provider_type (account); - - if (g_strcmp0 (provider_type, "kerberos") != 0) - continue; - - ticketing = goa_object_peek_ticketing (object); - - if (ticketing == NULL) - continue; - - ensure_account_credentials (self, object); - } - } - - static void - on_got_client (GoaClient *client, - GAsyncResult *result, - GoaIdentityService *self) - { - GError *error; - - error = NULL; - - self->priv->client = goa_client_new_finish (result, &error); - - if (self->priv->client == NULL) - { -- goa_warning ("Could not create client: %s", error->message); -- return; -+ g_warning ("Could not create client: %s", error->message); -+ goto out; - } - - self->priv->accounts_manager = goa_client_get_manager (client); - - self->priv->identity_manager = goa_kerberos_identity_manager_new (NULL, &error); - - if (self->priv->identity_manager == NULL) - { -- goa_warning ("Could not create identity manager: %s", error->message); -- return; -+ g_warning ("Could not create identity manager: %s", error->message); -+ goto out; - } - - goa_identity_manager_list_identities (self->priv->identity_manager, - NULL, - (GAsyncReadyCallback) - on_identities_listed, -- self); -+ g_object_ref (self)); - - ensure_credentials_for_accounts (self); -+ -+ out: -+ g_object_unref (self); - } - - static void - on_session_bus_acquired (GDBusConnection *connection, - const char *unique_name, - GoaIdentityService *self) - { - goa_debug ("GoaIdentityService: Connected to session bus"); - - if (self->priv->connection == NULL) - { - self->priv->connection = g_object_ref (connection); - - g_dbus_object_manager_server_set_connection (self->priv->object_manager_server, - self->priv->connection); - - goa_client_new (NULL, - (GAsyncReadyCallback) - on_got_client, -- self); -+ g_object_ref (self)); - } - } - - static void - on_name_acquired (GDBusConnection *connection, - const char *name, - GoaIdentityService *self) - { - if (g_strcmp0 (name, "org.gnome.Identity") == 0) - goa_debug ("GoaIdentityService: Acquired name org.gnome.Identity"); - } - - static void - on_name_lost (GDBusConnection *connection, - const char *name, - GoaIdentityService *self) - { - if (g_strcmp0 (name, "org.gnome.Identity") == 0) - goa_debug ("GoaIdentityService: Lost name org.gnome.Identity"); - } - - gboolean - goa_identity_service_activate (GoaIdentityService *self, - GError **error) - { - GoaIdentityServiceObjectSkeleton *object; - - g_return_val_if_fail (GOA_IS_IDENTITY_SERVICE (self), FALSE); - - goa_debug ("GoaIdentityService: Activating identity service"); --- -1.8.3.1 - - -From 24f2a2a6ded35cfc5afd1ebbb04a3b7d7351116e Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Fri, 9 May 2014 07:14:42 -0400 -Subject: [PATCH 14/24] goaalarm: small memory leak fix - -I was looking through a valgrind log and noticed this: - -==30104== -==30104== 40 bytes in 1 blocks are possibly lost in loss record 1,472 of -2,959 -==30104== at 0x4C2845D: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) -==30104== by 0xB6BD996: standard_malloc (gmem.c:85) -==30104== by 0xB6BDAAC: g_malloc (gmem.c:159) -==30104== by 0xB6DA0CE: g_slice_alloc (gslice.c:1003) -==30104== by 0xB71295A: g_rec_mutex_impl_new (gthread-posix.c:271) -==30104== by 0xB712AA8: g_rec_mutex_init (gthread-posix.c:339) -==30104== by 0x41B7C6: goa_alarm_init (goaalarm.c:174) -==30104== by 0xB4332B7: g_type_create_instance (gtype.c:1917) -==30104== by 0xB416A5D: g_object_constructor (gobject.c:1855) -==30104== by 0xB416149: g_object_newv (gobject.c:1719) -==30104== by 0xB4169B2: g_object_new_valist (gobject.c:1836) -==30104== by 0xB415AB8: g_object_new (gobject.c:1551) - -This commit adds the missing g_rec_mutex_clear call. - -https://bugzilla.gnome.org/show_bug.cgi?id=729864 ---- - src/goaidentity/goaalarm.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/src/goaidentity/goaalarm.c b/src/goaidentity/goaalarm.c -index 5f50243..0b5aad0 100644 ---- a/src/goaidentity/goaalarm.c -+++ b/src/goaidentity/goaalarm.c -@@ -146,60 +146,62 @@ clear_scheduled_wakeups (GoaAlarm *self) - case GOA_ALARM_TYPE_TIMEOUT: - clear_scheduled_timeout_wakeups (self); - break; - - default: - break; - } - - g_clear_object (&self->priv->cancellable); - - g_clear_pointer (&self->priv->context, (GDestroyNotify) g_main_context_unref); - - g_clear_pointer (&self->priv->previous_wakeup_time, - (GDestroyNotify) g_date_time_unref); - - g_clear_pointer (&self->priv->time, (GDestroyNotify) g_date_time_unref); - - g_assert (self->priv->timeout.source == NULL); - - self->priv->type = GOA_ALARM_TYPE_UNSCHEDULED; - g_rec_mutex_unlock (&self->priv->lock); - } - - static void - goa_alarm_finalize (GObject *object) - { - GoaAlarm *self = GOA_ALARM (object); - - clear_scheduled_wakeups (self); - -+ g_rec_mutex_clear (&self->priv->lock); -+ - G_OBJECT_CLASS (goa_alarm_parent_class)->finalize (object); - } - - static void - goa_alarm_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *param_spec) - { - GoaAlarm *self = GOA_ALARM (object); - GDateTime *time; - - switch (property_id) - { - case PROP_TIME: - time = (GDateTime *) g_value_get_boxed (value); - goa_alarm_set_time (self, time, self->priv->cancellable); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec); - break; - } - } - - static void - goa_alarm_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *param_spec) - { --- -1.8.3.1 - - -From 8a4ecda67cc848f1a4a1c212061f66850359a23e Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Fri, 9 May 2014 07:29:45 -0400 -Subject: [PATCH 15/24] identity: fix another principal leak - -Spotted by valgrind. - -https://bugzilla.gnome.org/show_bug.cgi?id=729865 ---- - src/goaidentity/goakerberosidentity.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/src/goaidentity/goakerberosidentity.c b/src/goaidentity/goakerberosidentity.c -index 9308295..f06bf30 100644 ---- a/src/goaidentity/goakerberosidentity.c -+++ b/src/goaidentity/goakerberosidentity.c -@@ -216,112 +216,114 @@ goa_kerberos_identity_class_init (GoaKerberosIdentityClass *klass) - NULL, - NULL, - NULL, - G_TYPE_NONE, - 0); - signals[NEEDS_REFRESH] = g_signal_new ("needs-refresh", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 0); - - g_object_class_override_property (object_class, PROP_IDENTIFIER, "identifier"); - g_object_class_override_property (object_class, PROP_IS_SIGNED_IN, "is-signed-in"); - g_object_class_override_property (object_class, - PROP_EXPIRATION_TIMESTAMP, - "expiration-timestamp"); - - } - - static char * - get_identifier (GoaKerberosIdentity *self, - GError **error) - { - krb5_principal principal; - krb5_error_code error_code; - char *unparsed_name; -- char *identifier; -+ char *identifier = NULL; - - if (self->priv->credentials_cache == NULL) - return NULL; - - error_code = krb5_cc_get_principal (self->priv->kerberos_context, - self->priv->credentials_cache, - &principal); - - if (error_code != 0) - { - if (error_code == KRB5_CC_END) - { - set_error_from_krb5_error_code (self, - error, - GOA_IDENTITY_ERROR_CREDENTIALS_UNAVAILABLE, - error_code, - _ - ("Could not find identity in credential cache: %k")); - } - else - { - set_error_from_krb5_error_code (self, - error, - GOA_IDENTITY_ERROR_ENUMERATING_CREDENTIALS, - error_code, - _ - ("Could not find identity in credential cache: %k")); - } - return NULL; - } - - error_code = krb5_unparse_name_flags (self->priv->kerberos_context, - principal, - 0, - &unparsed_name); - - if (error_code != 0) - { - const char *error_message; - - error_message = - krb5_get_error_message (self->priv->kerberos_context, error_code); - goa_debug ("GoaKerberosIdentity: Error parsing principal identity name: %s", - error_message); - krb5_free_error_message (self->priv->kerberos_context, error_message); -- return NULL; -+ goto out; - } - - identifier = g_strdup (unparsed_name); - krb5_free_unparsed_name (self->priv->kerberos_context, unparsed_name); - -+out: -+ krb5_free_principal (self->priv->kerberos_context, principal); - return identifier; - } - - static void - goa_kerberos_identity_init (GoaKerberosIdentity *self) - { - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - GOA_TYPE_KERBEROS_IDENTITY, - GoaKerberosIdentityPrivate); - self->priv->expiration_alarm = goa_alarm_new (); - self->priv->expiring_alarm = goa_alarm_new (); - self->priv->renewal_alarm = goa_alarm_new (); - } - - static void - set_error_from_krb5_error_code (GoaKerberosIdentity *self, - GError **error, - gint code, - krb5_error_code error_code, - const char *format, - ...) - { - const char *error_message; - char *literal_message; - char *expanded_format; - va_list args; - char **chunks; - - error_message = krb5_get_error_message (self->priv->kerberos_context, error_code); - chunks = g_strsplit (format, "%k", -1); --- -1.8.3.1 - - -From 63bc1591258f7543a393b1476bd067b79ad3134d Mon Sep 17 00:00:00 2001 -From: Debarshi Ray -Date: Fri, 8 Nov 2013 18:33:49 +0100 -Subject: [PATCH 16/24] alarm: Do not clear the wrong objects when setting the - time - -When the time is set using goa_alarm_set_time, we cancel the existing -self->priv->cancellable and replace it with a new one. Then we take a -reference to a new context and time. However, since when we cancelled -the old cancellable, we triggered a chain of events which cause -clear_scheduled_wakeups to be invoked from a idle callback. By the time -it gets invoked, self->priv->cancellable, self->priv->context and -self->priv->time point to the new objects that were set up in -goa_alarm_set_time, which we don't want to clear. - -Actually, there is no point in clearing them in -clear_scheduled_wakeups, because goa_alarm_set_time already clears up -the older objects and the only other time we want to clear them is in -dispose. - -Fixes: https://bugzilla.gnome.org/711696 ---- - src/goaidentity/goaalarm.c | 20 ++++++++++++++------ - 1 file changed, 14 insertions(+), 6 deletions(-) - -diff --git a/src/goaidentity/goaalarm.c b/src/goaidentity/goaalarm.c -index 0b5aad0..fa6b47d 100644 ---- a/src/goaidentity/goaalarm.c -+++ b/src/goaidentity/goaalarm.c -@@ -124,134 +124,141 @@ clear_scheduled_timer_wakeups (GoaAlarm *self) - g_clear_object (&self->priv->timer.stream); - #endif - } - - static void - clear_scheduled_timeout_wakeups (GoaAlarm *self) - { - g_clear_pointer (&self->priv->timeout.source, (GDestroyNotify) g_source_destroy); - } - - static void - clear_scheduled_wakeups (GoaAlarm *self) - { - g_rec_mutex_lock (&self->priv->lock); - clear_scheduled_immediate_wakeup (self); - - switch (self->priv->type) - { - case GOA_ALARM_TYPE_TIMER: - clear_scheduled_timer_wakeups (self); - break; - - case GOA_ALARM_TYPE_TIMEOUT: - clear_scheduled_timeout_wakeups (self); - break; - - default: - break; - } - -- g_clear_object (&self->priv->cancellable); -- -- g_clear_pointer (&self->priv->context, (GDestroyNotify) g_main_context_unref); -- - g_clear_pointer (&self->priv->previous_wakeup_time, - (GDestroyNotify) g_date_time_unref); - -- g_clear_pointer (&self->priv->time, (GDestroyNotify) g_date_time_unref); -- - g_assert (self->priv->timeout.source == NULL); - - self->priv->type = GOA_ALARM_TYPE_UNSCHEDULED; - g_rec_mutex_unlock (&self->priv->lock); - } - - static void -+goa_alarm_dispose (GObject *object) -+{ -+ GoaAlarm *self = GOA_ALARM (object); -+ -+ g_clear_object (&self->priv->cancellable); -+ g_clear_pointer (&self->priv->context, (GDestroyNotify) g_main_context_unref); -+ g_clear_pointer (&self->priv->time, (GDestroyNotify) g_date_time_unref); -+ -+ G_OBJECT_CLASS (goa_alarm_parent_class)->dispose (object); -+} -+ -+static void - goa_alarm_finalize (GObject *object) - { - GoaAlarm *self = GOA_ALARM (object); - - clear_scheduled_wakeups (self); - - g_rec_mutex_clear (&self->priv->lock); - - G_OBJECT_CLASS (goa_alarm_parent_class)->finalize (object); - } - - static void - goa_alarm_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *param_spec) - { - GoaAlarm *self = GOA_ALARM (object); - GDateTime *time; - - switch (property_id) - { - case PROP_TIME: - time = (GDateTime *) g_value_get_boxed (value); - goa_alarm_set_time (self, time, self->priv->cancellable); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec); - break; - } - } - - static void - goa_alarm_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *param_spec) - { - GoaAlarm *self = GOA_ALARM (object); - - switch (property_id) - { - case PROP_TIME: - g_value_set_boxed (value, self->priv->time); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec); - break; - } - } - - static void - goa_alarm_class_init (GoaAlarmClass *klass) - { - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS (klass); - -+ object_class->dispose = goa_alarm_dispose; - object_class->finalize = goa_alarm_finalize; - object_class->get_property = goa_alarm_get_property; - object_class->set_property = goa_alarm_set_property; - - g_type_class_add_private (klass, sizeof (GoaAlarmPrivate)); - - signals[FIRED] = g_signal_new ("fired", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, NULL, NULL, NULL, G_TYPE_NONE, 0); - - signals[REARMED] = g_signal_new ("rearmed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, NULL, NULL, NULL, G_TYPE_NONE, 0); - - g_object_class_install_property (object_class, - PROP_TIME, - g_param_spec_boxed ("time", - _("Time"), - _("Time to fire"), - G_TYPE_DATE_TIME, - G_PARAM_READWRITE)); - } - - static void - goa_alarm_init (GoaAlarm *self) - { - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GOA_TYPE_ALARM, GoaAlarmPrivate); - self->priv->type = GOA_ALARM_TYPE_UNSCHEDULED; -@@ -612,55 +619,56 @@ goa_alarm_set_time (GoaAlarm *self, GDateTime *time, GCancellable *cancellable) - return; - - g_rec_mutex_lock (&self->priv->lock); - if (self->priv->cancellable != NULL && self->priv->cancellable != cancellable) - g_cancellable_cancel (self->priv->cancellable); - - if (cancellable != NULL) - g_object_ref (cancellable); - - if (self->priv->cancelled_id != 0) - g_cancellable_disconnect (self->priv->cancellable, self->priv->cancelled_id); - - g_clear_object (&self->priv->cancellable); - - if (cancellable != NULL) - self->priv->cancellable = cancellable; - else - self->priv->cancellable = g_cancellable_new (); - - self->priv->cancelled_id = g_cancellable_connect (self->priv->cancellable, - G_CALLBACK (on_cancelled), - self, NULL); - - g_date_time_ref (time); - - if (self->priv->time != NULL) - g_date_time_unref (self->priv->time); - - self->priv->time = time; - -+ g_clear_pointer (&self->priv->context, (GDestroyNotify) g_main_context_unref); - self->priv->context = g_main_context_ref (g_main_context_default ()); - - schedule_wakeups (self); - - /* Wake up right away, in case it's already expired leaving the gate */ - schedule_immediate_wakeup (self); - g_rec_mutex_unlock (&self->priv->lock); - g_object_notify (G_OBJECT (self), "time"); - } - - GDateTime * - goa_alarm_get_time (GoaAlarm *self) - { - return self->priv->time; - } - - GoaAlarm * - goa_alarm_new (void) - { - GoaAlarm *self; - - self = GOA_ALARM (g_object_new (GOA_TYPE_ALARM, NULL)); - - return GOA_ALARM (self); - } --- -1.8.3.1 - - -From 0cf1b2a66d564cf234e401ea86bb3ca4615ff4d8 Mon Sep 17 00:00:00 2001 -From: Debarshi Ray -Date: Fri, 8 Nov 2013 18:36:46 +0100 -Subject: [PATCH 17/24] alarm: The global default main context is always the - same - -Fixes: https://bugzilla.gnome.org/711696 ---- - src/goaidentity/goaalarm.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/goaidentity/goaalarm.c b/src/goaidentity/goaalarm.c -index fa6b47d..18ca90c 100644 ---- a/src/goaidentity/goaalarm.c -+++ b/src/goaidentity/goaalarm.c -@@ -619,56 +619,56 @@ goa_alarm_set_time (GoaAlarm *self, GDateTime *time, GCancellable *cancellable) - return; - - g_rec_mutex_lock (&self->priv->lock); - if (self->priv->cancellable != NULL && self->priv->cancellable != cancellable) - g_cancellable_cancel (self->priv->cancellable); - - if (cancellable != NULL) - g_object_ref (cancellable); - - if (self->priv->cancelled_id != 0) - g_cancellable_disconnect (self->priv->cancellable, self->priv->cancelled_id); - - g_clear_object (&self->priv->cancellable); - - if (cancellable != NULL) - self->priv->cancellable = cancellable; - else - self->priv->cancellable = g_cancellable_new (); - - self->priv->cancelled_id = g_cancellable_connect (self->priv->cancellable, - G_CALLBACK (on_cancelled), - self, NULL); - - g_date_time_ref (time); - - if (self->priv->time != NULL) - g_date_time_unref (self->priv->time); - - self->priv->time = time; - -- g_clear_pointer (&self->priv->context, (GDestroyNotify) g_main_context_unref); -- self->priv->context = g_main_context_ref (g_main_context_default ()); -+ if (self->priv->context == NULL) -+ self->priv->context = g_main_context_ref (g_main_context_default ()); - - schedule_wakeups (self); - - /* Wake up right away, in case it's already expired leaving the gate */ - schedule_immediate_wakeup (self); - g_rec_mutex_unlock (&self->priv->lock); - g_object_notify (G_OBJECT (self), "time"); - } - - GDateTime * - goa_alarm_get_time (GoaAlarm *self) - { - return self->priv->time; - } - - GoaAlarm * - goa_alarm_new (void) - { - GoaAlarm *self; - - self = GOA_ALARM (g_object_new (GOA_TYPE_ALARM, NULL)); - - return GOA_ALARM (self); - } --- -1.8.3.1 - - -From ecd08c1b24aa7160f1ab208ea454be5d3b275bab Mon Sep 17 00:00:00 2001 -From: Debarshi Ray -Date: Mon, 11 Nov 2013 11:51:42 +0100 -Subject: [PATCH 18/24] alarm: Use the same GSource pointer for TIMER and - TIMEOUT alarms - -Simplifies the code so that it is easier to tag the "cancelled" -handler with the correct GSource and GInputStream (if any) that are to -be cleaned. - -Fixes: https://bugzilla.gnome.org/711696 ---- - src/goaidentity/goaalarm.c | 50 ++++++++++++++++------------------------------ - 1 file changed, 17 insertions(+), 33 deletions(-) - -diff --git a/src/goaidentity/goaalarm.c b/src/goaidentity/goaalarm.c -index 18ca90c..f5a1dfb 100644 ---- a/src/goaidentity/goaalarm.c -+++ b/src/goaidentity/goaalarm.c -@@ -1,188 +1,172 @@ - /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - /* -- * Copyright (C) 2012 Red Hat, Inc. -+ * Copyright (C) 2012, 2013 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Ray Strode - * Based on work by Colin Walters - */ - - #include "config.h" - - #include "goaalarm.h" - - #ifdef HAVE_TIMERFD - #include - #endif - - #include - #include - - #include - #include - #include - #include - - #include "goalogging.h" - --typedef struct --{ -- GSource *source; -- GInputStream *stream; --} Timer; -- --typedef struct --{ -- GSource *source; --} Timeout; -- - #define MAX_TIMEOUT_INTERVAL (10 *1000) - - typedef enum - { - GOA_ALARM_TYPE_UNSCHEDULED, - GOA_ALARM_TYPE_TIMER, - GOA_ALARM_TYPE_TIMEOUT, - } GoaAlarmType; - - struct _GoaAlarmPrivate - { - GCancellable *cancellable; - gulong cancelled_id; - GDateTime *time; - GDateTime *previous_wakeup_time; - GMainContext *context; - GSource *immediate_wakeup_source; - GRecMutex lock; - - GoaAlarmType type; -- union -- { -- Timer timer; -- Timeout timeout; -- }; -+ GSource *scheduled_wakeup_source; -+ GInputStream *stream; /* NULL, unless using timerfd */ - }; - - enum - { - FIRED, - REARMED, - NUMBER_OF_SIGNALS, - }; - - enum - { - PROP_0, - PROP_TIME - }; - - static void schedule_wakeups (GoaAlarm *self); - static void schedule_wakeups_with_timeout_source (GoaAlarm *self); - static guint signals[NUMBER_OF_SIGNALS] = { 0 }; - - G_DEFINE_TYPE (GoaAlarm, goa_alarm, G_TYPE_OBJECT); - - static void - clear_scheduled_immediate_wakeup (GoaAlarm *self) - { - g_clear_pointer (&self->priv->immediate_wakeup_source, - (GDestroyNotify) g_source_destroy); - } - - static void - clear_scheduled_timer_wakeups (GoaAlarm *self) - { - #ifdef HAVE_TIMERFD - GError *error; - gboolean is_closed; - -- g_clear_pointer (&self->priv->timer.source, (GDestroyNotify) g_source_destroy); -+ g_clear_pointer (&self->priv->scheduled_wakeup_source, (GDestroyNotify) g_source_destroy); - - error = NULL; -- is_closed = g_input_stream_close (self->priv->timer.stream, NULL, &error); -+ is_closed = g_input_stream_close (self->priv->stream, NULL, &error); - - if (!is_closed) - { - goa_warning ("GoaAlarm: could not close timer stream: %s", error->message); - g_error_free (error); - } - -- g_clear_object (&self->priv->timer.stream); -+ g_clear_object (&self->priv->stream); - #endif - } - - static void - clear_scheduled_timeout_wakeups (GoaAlarm *self) - { -- g_clear_pointer (&self->priv->timeout.source, (GDestroyNotify) g_source_destroy); -+ g_clear_pointer (&self->priv->scheduled_wakeup_source, (GDestroyNotify) g_source_destroy); - } - - static void - clear_scheduled_wakeups (GoaAlarm *self) - { - g_rec_mutex_lock (&self->priv->lock); - clear_scheduled_immediate_wakeup (self); - - switch (self->priv->type) - { - case GOA_ALARM_TYPE_TIMER: - clear_scheduled_timer_wakeups (self); - break; - - case GOA_ALARM_TYPE_TIMEOUT: - clear_scheduled_timeout_wakeups (self); - break; - - default: - break; - } - - g_clear_pointer (&self->priv->previous_wakeup_time, - (GDestroyNotify) g_date_time_unref); - -- g_assert (self->priv->timeout.source == NULL); -- - self->priv->type = GOA_ALARM_TYPE_UNSCHEDULED; - g_rec_mutex_unlock (&self->priv->lock); - } - - static void - goa_alarm_dispose (GObject *object) - { - GoaAlarm *self = GOA_ALARM (object); - - g_clear_object (&self->priv->cancellable); - g_clear_pointer (&self->priv->context, (GDestroyNotify) g_main_context_unref); - g_clear_pointer (&self->priv->time, (GDestroyNotify) g_date_time_unref); - - G_OBJECT_CLASS (goa_alarm_parent_class)->dispose (object); - } - - static void - goa_alarm_finalize (GObject *object) - { - GoaAlarm *self = GOA_ALARM (object); - - clear_scheduled_wakeups (self); - - g_rec_mutex_clear (&self->priv->lock); - - G_OBJECT_CLASS (goa_alarm_parent_class)->finalize (object); - } - - static void - goa_alarm_set_property (GObject *object, -@@ -410,188 +394,188 @@ on_timer_source_ready (GObject *stream, GTask *task) - if (bytes_read < 0) - { - goa_warning ("GoaAlarm: failed to read from timer fd: %s\n", - error->message); - g_error_free (error); - goto out; - } - - if (bytes_read == sizeof (gint64)) - { - if (number_of_fires < 0 || number_of_fires > 1) - { - goa_warning ("GoaAlarm: expected timerfd to report firing once," - "but it reported firing %ld times\n", (long) number_of_fires); - } - } - - fire_or_rearm_alarm (self); - run_again = TRUE; - out: - g_rec_mutex_unlock (&self->priv->lock); - return run_again; - } - - static void - clear_timer_source (GTask *task) - { - GoaAlarm *self; - - self = g_task_get_source_object (task); -- self->priv->timer.source = NULL; -+ self->priv->scheduled_wakeup_source = NULL; - - g_object_unref (task); - } - #endif - - static gboolean - schedule_wakeups_with_timerfd (GoaAlarm *self) - { - #ifdef HAVE_TIMERFD - struct itimerspec timer_spec; - int fd; - int result; - GSource *source; - GTask *task; - static gboolean seen_before = FALSE; - - if (!seen_before) - { - goa_debug ("GoaAlarm: trying to use kernel timer"); - seen_before = TRUE; - } - - fd = timerfd_create (CLOCK_REALTIME, TFD_CLOEXEC | TFD_NONBLOCK); - - if (fd < 0) - { - goa_debug ("GoaAlarm: could not create timer fd: %m"); - return FALSE; - } - - memset (&timer_spec, 0, sizeof (timer_spec)); - timer_spec.it_value.tv_sec = g_date_time_to_unix (self->priv->time) + 1; - - result = timerfd_settime (fd, - TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, - &timer_spec, NULL); - - if (result < 0) - { - goa_debug ("GoaAlarm: could not set timer: %m"); - return FALSE; - } - - self->priv->type = GOA_ALARM_TYPE_TIMER; -- self->priv->timer.stream = g_unix_input_stream_new (fd, TRUE); -+ self->priv->stream = g_unix_input_stream_new (fd, TRUE); - - task = g_task_new (self, self->priv->cancellable, NULL, NULL); - - source = - g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM -- (self->priv->timer.stream), -+ (self->priv->stream), - self->priv->cancellable); -- self->priv->timer.source = source; -- g_source_set_callback (self->priv->timer.source, -+ self->priv->scheduled_wakeup_source = source; -+ g_source_set_callback (self->priv->scheduled_wakeup_source, - (GSourceFunc) on_timer_source_ready, task, - (GDestroyNotify) clear_timer_source); -- g_source_attach (self->priv->timer.source, self->priv->context); -+ g_source_attach (self->priv->scheduled_wakeup_source, self->priv->context); - g_source_unref (source); - - return TRUE; - - #endif /*HAVE_TIMERFD */ - - return FALSE; - } - - static gboolean - on_timeout_source_ready (GoaAlarm *self) - { - g_return_val_if_fail (GOA_IS_ALARM (self), FALSE); - - g_rec_mutex_lock (&self->priv->lock); - - if (g_cancellable_is_cancelled (self->priv->cancellable) || - self->priv->type == GOA_ALARM_TYPE_UNSCHEDULED) - goto out; - - fire_or_rearm_alarm (self); - - if (g_cancellable_is_cancelled (self->priv->cancellable)) - goto out; - - schedule_wakeups_with_timeout_source (self); - - out: - g_rec_mutex_unlock (&self->priv->lock); - return FALSE; - } - - static void - clear_timeout_source_pointer (GoaAlarm *self) - { -- self->priv->timeout.source = NULL; -+ self->priv->scheduled_wakeup_source = NULL; - } - - static void - schedule_wakeups_with_timeout_source (GoaAlarm *self) - { - GDateTime *now; - GSource *source; - GTimeSpan time_span; - guint interval; - - self->priv->type = GOA_ALARM_TYPE_TIMEOUT; - - now = g_date_time_new_now_local (); - time_span = g_date_time_difference (self->priv->time, now); - g_date_time_unref (now); - - time_span = - CLAMP (time_span, 1000 *G_TIME_SPAN_MILLISECOND, - G_MAXUINT *G_TIME_SPAN_MILLISECOND); - interval = (guint) time_span / G_TIME_SPAN_MILLISECOND; - - /* We poll every 10 seconds or so because we want to catch time skew - */ - interval = MIN (interval, MAX_TIMEOUT_INTERVAL); - - source = g_timeout_source_new (interval); - -- self->priv->timeout.source = source; -- g_source_set_callback (self->priv->timeout.source, -+ self->priv->scheduled_wakeup_source = source; -+ g_source_set_callback (self->priv->scheduled_wakeup_source, - (GSourceFunc) - on_timeout_source_ready, - self, (GDestroyNotify) clear_timeout_source_pointer); - -- g_source_attach (self->priv->timeout.source, self->priv->context); -+ g_source_attach (self->priv->scheduled_wakeup_source, self->priv->context); - g_source_unref (source); - } - - static void - schedule_wakeups (GoaAlarm *self) - { - gboolean wakeup_scheduled; - - wakeup_scheduled = schedule_wakeups_with_timerfd (self); - - if (!wakeup_scheduled) - { - static gboolean seen_before = FALSE; - - if (!seen_before) - { - goa_debug ("GoaAlarm: falling back to polling timeout"); - seen_before = TRUE; - } - schedule_wakeups_with_timeout_source (self); - } - } - - static void - clear_immediate_wakeup_source_pointer (GoaAlarm *self) - { - self->priv->immediate_wakeup_source = NULL; - } - - static void --- -1.8.3.1 - - -From 553fea89083bbaa32a96cee23eede4317ecc817d Mon Sep 17 00:00:00 2001 -From: Debarshi Ray -Date: Mon, 11 Nov 2013 13:11:28 +0100 -Subject: [PATCH 19/24] alarm: Tag the "cancelled" handler with the correct - source and stream - -When a time is set using goa_alarm_set_time, we try to clear the older -source and stream by cancelling self->priv->cancellable. However, -before we have had a chance to actually clear them in an idle callback, -a new source and stream corresponding to the new time is set. This -causes the older source and stream to be leaked, and instead the newly -created objects are cleared. - -This is wrong. To set things right, we tag the cancelled handler with -the older source and stream before they are overwritten. - -Fixes: https://bugzilla.gnome.org/711696 ---- - src/goaidentity/goaalarm.c | 60 +++++++++++++++++++++++++++------------------- - 1 file changed, 35 insertions(+), 25 deletions(-) - -diff --git a/src/goaidentity/goaalarm.c b/src/goaidentity/goaalarm.c -index f5a1dfb..68a6c46 100644 ---- a/src/goaidentity/goaalarm.c -+++ b/src/goaidentity/goaalarm.c -@@ -63,132 +63,132 @@ struct _GoaAlarmPrivate - GInputStream *stream; /* NULL, unless using timerfd */ - }; - - enum - { - FIRED, - REARMED, - NUMBER_OF_SIGNALS, - }; - - enum - { - PROP_0, - PROP_TIME - }; - - static void schedule_wakeups (GoaAlarm *self); - static void schedule_wakeups_with_timeout_source (GoaAlarm *self); - static guint signals[NUMBER_OF_SIGNALS] = { 0 }; - - G_DEFINE_TYPE (GoaAlarm, goa_alarm, G_TYPE_OBJECT); - - static void - clear_scheduled_immediate_wakeup (GoaAlarm *self) - { - g_clear_pointer (&self->priv->immediate_wakeup_source, - (GDestroyNotify) g_source_destroy); - } - - static void --clear_scheduled_timer_wakeups (GoaAlarm *self) -+clear_scheduled_timer_wakeups (GoaAlarm *self, GSource *source, GInputStream *stream) - { - #ifdef HAVE_TIMERFD - GError *error; - gboolean is_closed; - -- g_clear_pointer (&self->priv->scheduled_wakeup_source, (GDestroyNotify) g_source_destroy); -+ g_source_destroy (source); - - error = NULL; -- is_closed = g_input_stream_close (self->priv->stream, NULL, &error); -+ is_closed = g_input_stream_close (stream, NULL, &error); - - if (!is_closed) - { - goa_warning ("GoaAlarm: could not close timer stream: %s", error->message); - g_error_free (error); - } - -- g_clear_object (&self->priv->stream); -+ g_object_unref (stream); - #endif - } - - static void --clear_scheduled_timeout_wakeups (GoaAlarm *self) -+clear_scheduled_timeout_wakeups (GoaAlarm *self, GSource *source) - { -- g_clear_pointer (&self->priv->scheduled_wakeup_source, (GDestroyNotify) g_source_destroy); -+ g_source_destroy (source); - } - - static void --clear_scheduled_wakeups (GoaAlarm *self) -+clear_scheduled_wakeups (GoaAlarm *self, GSource *source, GInputStream *stream) - { - g_rec_mutex_lock (&self->priv->lock); - clear_scheduled_immediate_wakeup (self); - - switch (self->priv->type) - { - case GOA_ALARM_TYPE_TIMER: -- clear_scheduled_timer_wakeups (self); -+ clear_scheduled_timer_wakeups (self, source, stream); - break; - - case GOA_ALARM_TYPE_TIMEOUT: -- clear_scheduled_timeout_wakeups (self); -+ clear_scheduled_timeout_wakeups (self, source); - break; - - default: - break; - } - - g_clear_pointer (&self->priv->previous_wakeup_time, - (GDestroyNotify) g_date_time_unref); - - self->priv->type = GOA_ALARM_TYPE_UNSCHEDULED; - g_rec_mutex_unlock (&self->priv->lock); - } - - static void - goa_alarm_dispose (GObject *object) - { - GoaAlarm *self = GOA_ALARM (object); - - g_clear_object (&self->priv->cancellable); - g_clear_pointer (&self->priv->context, (GDestroyNotify) g_main_context_unref); - g_clear_pointer (&self->priv->time, (GDestroyNotify) g_date_time_unref); - - G_OBJECT_CLASS (goa_alarm_parent_class)->dispose (object); - } - - static void - goa_alarm_finalize (GObject *object) - { - GoaAlarm *self = GOA_ALARM (object); - -- clear_scheduled_wakeups (self); -+ clear_scheduled_wakeups (self, self->priv->scheduled_wakeup_source, self->priv->stream); - - g_rec_mutex_clear (&self->priv->lock); - - G_OBJECT_CLASS (goa_alarm_parent_class)->finalize (object); - } - - static void - goa_alarm_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *param_spec) - { - GoaAlarm *self = GOA_ALARM (object); - GDateTime *time; - - switch (property_id) - { - case PROP_TIME: - time = (GDateTime *) g_value_get_boxed (value); - goa_alarm_set_time (self, time, self->priv->cancellable); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec); - break; - } - } - - static void - goa_alarm_get_property (GObject *object, - guint property_id, -@@ -225,78 +225,99 @@ goa_alarm_class_init (GoaAlarmClass *klass) - signals[FIRED] = g_signal_new ("fired", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, NULL, NULL, NULL, G_TYPE_NONE, 0); - - signals[REARMED] = g_signal_new ("rearmed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, NULL, NULL, NULL, G_TYPE_NONE, 0); - - g_object_class_install_property (object_class, - PROP_TIME, - g_param_spec_boxed ("time", - _("Time"), - _("Time to fire"), - G_TYPE_DATE_TIME, - G_PARAM_READWRITE)); - } - - static void - goa_alarm_init (GoaAlarm *self) - { - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GOA_TYPE_ALARM, GoaAlarmPrivate); - self->priv->type = GOA_ALARM_TYPE_UNSCHEDULED; - g_rec_mutex_init (&self->priv->lock); - } - - static gboolean - async_alarm_cancel_idle_cb (gpointer user_data) - { -- GoaAlarm *self = user_data; -+ GoaAlarm *self; -+ GInputStream *stream; -+ GSource *source; -+ GTask *task = G_TASK (user_data); -+ gpointer task_data; - -- clear_scheduled_wakeups (self); -+ self = g_task_get_source_object (task); -+ source = (GSource *) g_object_get_data (G_OBJECT (task), "alarm-scheduled-wakeup-source"); -+ task_data = g_object_get_data (G_OBJECT (task), "alarm-stream"); -+ stream = (task_data == NULL) ? NULL : G_INPUT_STREAM (task_data); -+ -+ clear_scheduled_wakeups (self, source, stream); - return G_SOURCE_REMOVE; - } - - static void - on_cancelled (GCancellable *cancellable, gpointer user_data) - { - GoaAlarm *self = GOA_ALARM (user_data); - GSource *idle_source; -+ GTask *task; - -+ task = g_task_new (self, NULL, NULL, NULL); -+ -+ g_object_set_data_full (G_OBJECT (task), -+ "alarm-scheduled-wakeup-source", -+ g_source_ref (self->priv->scheduled_wakeup_source), -+ (GDestroyNotify) g_source_unref); -+ -+ if (self->priv->stream != NULL) -+ g_object_set_data_full (G_OBJECT (task), "alarm-stream", g_object_ref (self->priv->stream), g_object_unref); - - idle_source = g_idle_source_new (); - g_source_set_priority (idle_source, G_PRIORITY_HIGH_IDLE); -- g_source_set_callback (idle_source, async_alarm_cancel_idle_cb, g_object_ref (self), g_object_unref); -+ g_source_set_callback (idle_source, async_alarm_cancel_idle_cb, g_object_ref (task), g_object_unref); - g_source_attach (idle_source, self->priv->context); - g_source_unref (idle_source); -+ -+ g_object_unref (task); - } - - static void - fire_alarm (GoaAlarm *self) - { - g_signal_emit (G_OBJECT (self), signals[FIRED], 0); - } - - static void - rearm_alarm (GoaAlarm *self) - { - g_signal_emit (G_OBJECT (self), signals[REARMED], 0); - } - - static void - fire_or_rearm_alarm (GoaAlarm *self) - { - GTimeSpan time_until_fire; - GTimeSpan previous_time_until_fire; - GDateTime *now; - - now = g_date_time_new_now_local (); - time_until_fire = g_date_time_difference (self->priv->time, now); - - if (self->priv->previous_wakeup_time == NULL) - { - self->priv->previous_wakeup_time = now; - - /* If, according to the time, we're past when we should have fired, - * then fire the alarm. -@@ -387,124 +408,113 @@ on_timer_source_ready (GObject *stream, GTask *task) - goto out; - - bytes_read = - g_pollable_input_stream_read_nonblocking (G_POLLABLE_INPUT_STREAM (stream), - &number_of_fires, sizeof (gint64), - NULL, &error); - - if (bytes_read < 0) - { - goa_warning ("GoaAlarm: failed to read from timer fd: %s\n", - error->message); - g_error_free (error); - goto out; - } - - if (bytes_read == sizeof (gint64)) - { - if (number_of_fires < 0 || number_of_fires > 1) - { - goa_warning ("GoaAlarm: expected timerfd to report firing once," - "but it reported firing %ld times\n", (long) number_of_fires); - } - } - - fire_or_rearm_alarm (self); - run_again = TRUE; - out: - g_rec_mutex_unlock (&self->priv->lock); - return run_again; - } -- --static void --clear_timer_source (GTask *task) --{ -- GoaAlarm *self; -- -- self = g_task_get_source_object (task); -- self->priv->scheduled_wakeup_source = NULL; -- -- g_object_unref (task); --} - #endif - - static gboolean - schedule_wakeups_with_timerfd (GoaAlarm *self) - { - #ifdef HAVE_TIMERFD - struct itimerspec timer_spec; - int fd; - int result; - GSource *source; - GTask *task; - static gboolean seen_before = FALSE; - - if (!seen_before) - { - goa_debug ("GoaAlarm: trying to use kernel timer"); - seen_before = TRUE; - } - - fd = timerfd_create (CLOCK_REALTIME, TFD_CLOEXEC | TFD_NONBLOCK); - - if (fd < 0) - { - goa_debug ("GoaAlarm: could not create timer fd: %m"); - return FALSE; - } - - memset (&timer_spec, 0, sizeof (timer_spec)); - timer_spec.it_value.tv_sec = g_date_time_to_unix (self->priv->time) + 1; - - result = timerfd_settime (fd, - TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, - &timer_spec, NULL); - - if (result < 0) - { - goa_debug ("GoaAlarm: could not set timer: %m"); - return FALSE; - } - - self->priv->type = GOA_ALARM_TYPE_TIMER; - self->priv->stream = g_unix_input_stream_new (fd, TRUE); - - task = g_task_new (self, self->priv->cancellable, NULL, NULL); - - source = - g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM - (self->priv->stream), - self->priv->cancellable); - self->priv->scheduled_wakeup_source = source; - g_source_set_callback (self->priv->scheduled_wakeup_source, - (GSourceFunc) on_timer_source_ready, task, -- (GDestroyNotify) clear_timer_source); -+ (GDestroyNotify) g_object_unref); - g_source_attach (self->priv->scheduled_wakeup_source, self->priv->context); - g_source_unref (source); - - return TRUE; - - #endif /*HAVE_TIMERFD */ - - return FALSE; - } - - static gboolean - on_timeout_source_ready (GoaAlarm *self) - { - g_return_val_if_fail (GOA_IS_ALARM (self), FALSE); - - g_rec_mutex_lock (&self->priv->lock); - - if (g_cancellable_is_cancelled (self->priv->cancellable) || - self->priv->type == GOA_ALARM_TYPE_UNSCHEDULED) - goto out; - - fire_or_rearm_alarm (self); - - if (g_cancellable_is_cancelled (self->priv->cancellable)) - goto out; - - schedule_wakeups_with_timeout_source (self); - - out: - g_rec_mutex_unlock (&self->priv->lock); --- -1.8.3.1 - - -From 18e305912fbac9c56c21d0c5633a095ac4fe4176 Mon Sep 17 00:00:00 2001 -From: Debarshi Ray -Date: Mon, 11 Nov 2013 14:49:06 +0100 -Subject: [PATCH 20/24] alarm: Remove redundant preprocessor conditional - -Reading the rest of the code, it appears to me that the preprocessor -conditionals were meant to surpress compiler warnings and errors -caused by the lack of timerfd support. For the rest of the logic, -GoaAlarmType is used to separate the different kinds of timers. - -Fixes: https://bugzilla.gnome.org/711696 ---- - src/goaidentity/goaalarm.c | 2 -- - 1 file changed, 2 deletions(-) - -diff --git a/src/goaidentity/goaalarm.c b/src/goaidentity/goaalarm.c -index 68a6c46..4381f0b 100644 ---- a/src/goaidentity/goaalarm.c -+++ b/src/goaidentity/goaalarm.c -@@ -65,77 +65,75 @@ struct _GoaAlarmPrivate - - enum - { - FIRED, - REARMED, - NUMBER_OF_SIGNALS, - }; - - enum - { - PROP_0, - PROP_TIME - }; - - static void schedule_wakeups (GoaAlarm *self); - static void schedule_wakeups_with_timeout_source (GoaAlarm *self); - static guint signals[NUMBER_OF_SIGNALS] = { 0 }; - - G_DEFINE_TYPE (GoaAlarm, goa_alarm, G_TYPE_OBJECT); - - static void - clear_scheduled_immediate_wakeup (GoaAlarm *self) - { - g_clear_pointer (&self->priv->immediate_wakeup_source, - (GDestroyNotify) g_source_destroy); - } - - static void - clear_scheduled_timer_wakeups (GoaAlarm *self, GSource *source, GInputStream *stream) - { --#ifdef HAVE_TIMERFD - GError *error; - gboolean is_closed; - - g_source_destroy (source); - - error = NULL; - is_closed = g_input_stream_close (stream, NULL, &error); - - if (!is_closed) - { - goa_warning ("GoaAlarm: could not close timer stream: %s", error->message); - g_error_free (error); - } - - g_object_unref (stream); --#endif - } - - static void - clear_scheduled_timeout_wakeups (GoaAlarm *self, GSource *source) - { - g_source_destroy (source); - } - - static void - clear_scheduled_wakeups (GoaAlarm *self, GSource *source, GInputStream *stream) - { - g_rec_mutex_lock (&self->priv->lock); - clear_scheduled_immediate_wakeup (self); - - switch (self->priv->type) - { - case GOA_ALARM_TYPE_TIMER: - clear_scheduled_timer_wakeups (self, source, stream); - break; - - case GOA_ALARM_TYPE_TIMEOUT: - clear_scheduled_timeout_wakeups (self, source); - break; - - default: - break; - } - - g_clear_pointer (&self->priv->previous_wakeup_time, - (GDestroyNotify) g_date_time_unref); --- -1.8.3.1 - - -From 108f318ecadad481dfd38b619d56c575484745bf Mon Sep 17 00:00:00 2001 -From: Debarshi Ray -Date: Tue, 12 Nov 2013 11:00:05 +0100 -Subject: [PATCH 21/24] alarm: Consolidate clear_scheduled_time*_wakeups into - one function - -Since we are using the same GSource pointer for TIMER and TIMEOUT -alarms, there is no reason to continue having separate functions. - -Fixes: https://bugzilla.gnome.org/711696 ---- - src/goaidentity/goaalarm.c | 52 +++++++++++++++------------------------------- - 1 file changed, 17 insertions(+), 35 deletions(-) - -diff --git a/src/goaidentity/goaalarm.c b/src/goaidentity/goaalarm.c -index 4381f0b..34d99f3 100644 ---- a/src/goaidentity/goaalarm.c -+++ b/src/goaidentity/goaalarm.c -@@ -63,103 +63,85 @@ struct _GoaAlarmPrivate - GInputStream *stream; /* NULL, unless using timerfd */ - }; - - enum - { - FIRED, - REARMED, - NUMBER_OF_SIGNALS, - }; - - enum - { - PROP_0, - PROP_TIME - }; - - static void schedule_wakeups (GoaAlarm *self); - static void schedule_wakeups_with_timeout_source (GoaAlarm *self); - static guint signals[NUMBER_OF_SIGNALS] = { 0 }; - - G_DEFINE_TYPE (GoaAlarm, goa_alarm, G_TYPE_OBJECT); - - static void - clear_scheduled_immediate_wakeup (GoaAlarm *self) - { - g_clear_pointer (&self->priv->immediate_wakeup_source, - (GDestroyNotify) g_source_destroy); - } - - static void --clear_scheduled_timer_wakeups (GoaAlarm *self, GSource *source, GInputStream *stream) --{ -- GError *error; -- gboolean is_closed; -- -- g_source_destroy (source); -- -- error = NULL; -- is_closed = g_input_stream_close (stream, NULL, &error); -- -- if (!is_closed) -- { -- goa_warning ("GoaAlarm: could not close timer stream: %s", error->message); -- g_error_free (error); -- } -- -- g_object_unref (stream); --} -- --static void --clear_scheduled_timeout_wakeups (GoaAlarm *self, GSource *source) --{ -- g_source_destroy (source); --} -- --static void - clear_scheduled_wakeups (GoaAlarm *self, GSource *source, GInputStream *stream) - { - g_rec_mutex_lock (&self->priv->lock); - clear_scheduled_immediate_wakeup (self); - -- switch (self->priv->type) -+ if (self->priv->type != GOA_ALARM_TYPE_UNSCHEDULED) - { -- case GOA_ALARM_TYPE_TIMER: -- clear_scheduled_timer_wakeups (self, source, stream); -- break; -+ g_source_destroy (source); - -- case GOA_ALARM_TYPE_TIMEOUT: -- clear_scheduled_timeout_wakeups (self, source); -- break; -+ if (stream != NULL) -+ { -+ GError *error; -+ gboolean is_closed; - -- default: -- break; -+ error = NULL; -+ is_closed = g_input_stream_close (stream, NULL, &error); -+ -+ if (!is_closed) -+ { -+ goa_warning ("GoaAlarm: could not close timer stream: %s", error->message); -+ g_error_free (error); -+ } -+ -+ g_object_unref (stream); -+ } - } - - g_clear_pointer (&self->priv->previous_wakeup_time, - (GDestroyNotify) g_date_time_unref); - - self->priv->type = GOA_ALARM_TYPE_UNSCHEDULED; - g_rec_mutex_unlock (&self->priv->lock); - } - - static void - goa_alarm_dispose (GObject *object) - { - GoaAlarm *self = GOA_ALARM (object); - - g_clear_object (&self->priv->cancellable); - g_clear_pointer (&self->priv->context, (GDestroyNotify) g_main_context_unref); - g_clear_pointer (&self->priv->time, (GDestroyNotify) g_date_time_unref); - - G_OBJECT_CLASS (goa_alarm_parent_class)->dispose (object); - } - - static void - goa_alarm_finalize (GObject *object) - { - GoaAlarm *self = GOA_ALARM (object); - - clear_scheduled_wakeups (self, self->priv->scheduled_wakeup_source, self->priv->stream); - - g_rec_mutex_clear (&self->priv->lock); - --- -1.8.3.1 - - -From 34fcfc59b52f18fac0ab8d94808aed55e10d5173 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Thu, 8 May 2014 13:31:16 -0400 -Subject: [PATCH 22/24] identity: dramatically simplify alarm logic - -The GoaAlarm code is unwieldy. Primarily this is because -it supports resetting the alarm after creation, but can't -clean up old state right away due to a bug in GLib -(bug 705395). All this complexitly is leading to bugs, and -caos. - -This commit introduces some zen to the situation by making -GoaAlarm immutable and much simpler. Now to reset an alarm, -the identity code just instantiates a new one and destroys the -old one. - -https://bugzilla.gnome.org/show_bug.cgi?id=729718 ---- - src/goaidentity/goaalarm.c | 177 ++++------------------------------ - src/goaidentity/goaalarm.h | 5 +- - src/goaidentity/goakerberosidentity.c | 131 ++++++++++++------------- - 3 files changed, 82 insertions(+), 231 deletions(-) - -diff --git a/src/goaidentity/goaalarm.c b/src/goaidentity/goaalarm.c -index 34d99f3..c86f665 100644 ---- a/src/goaidentity/goaalarm.c -+++ b/src/goaidentity/goaalarm.c -@@ -23,172 +23,131 @@ - - #include "config.h" - - #include "goaalarm.h" - - #ifdef HAVE_TIMERFD - #include - #endif - - #include - #include - - #include - #include - #include - #include - - #include "goalogging.h" - - #define MAX_TIMEOUT_INTERVAL (10 *1000) - - typedef enum - { - GOA_ALARM_TYPE_UNSCHEDULED, - GOA_ALARM_TYPE_TIMER, - GOA_ALARM_TYPE_TIMEOUT, - } GoaAlarmType; - - struct _GoaAlarmPrivate - { -- GCancellable *cancellable; -- gulong cancelled_id; - GDateTime *time; - GDateTime *previous_wakeup_time; - GMainContext *context; - GSource *immediate_wakeup_source; - GRecMutex lock; - - GoaAlarmType type; - GSource *scheduled_wakeup_source; - GInputStream *stream; /* NULL, unless using timerfd */ - }; - - enum - { - FIRED, - REARMED, - NUMBER_OF_SIGNALS, - }; - - enum - { - PROP_0, - PROP_TIME - }; - - static void schedule_wakeups (GoaAlarm *self); - static void schedule_wakeups_with_timeout_source (GoaAlarm *self); -+static void goa_alarm_set_time (GoaAlarm *self, GDateTime *time); -+static void clear_wakeup_source_pointer (GoaAlarm *self); - static guint signals[NUMBER_OF_SIGNALS] = { 0 }; - - G_DEFINE_TYPE (GoaAlarm, goa_alarm, G_TYPE_OBJECT); - - static void --clear_scheduled_immediate_wakeup (GoaAlarm *self) --{ -- g_clear_pointer (&self->priv->immediate_wakeup_source, -- (GDestroyNotify) g_source_destroy); --} -- --static void --clear_scheduled_wakeups (GoaAlarm *self, GSource *source, GInputStream *stream) --{ -- g_rec_mutex_lock (&self->priv->lock); -- clear_scheduled_immediate_wakeup (self); -- -- if (self->priv->type != GOA_ALARM_TYPE_UNSCHEDULED) -- { -- g_source_destroy (source); -- -- if (stream != NULL) -- { -- GError *error; -- gboolean is_closed; -- -- error = NULL; -- is_closed = g_input_stream_close (stream, NULL, &error); -- -- if (!is_closed) -- { -- goa_warning ("GoaAlarm: could not close timer stream: %s", error->message); -- g_error_free (error); -- } -- -- g_object_unref (stream); -- } -- } -- -- g_clear_pointer (&self->priv->previous_wakeup_time, -- (GDestroyNotify) g_date_time_unref); -- -- self->priv->type = GOA_ALARM_TYPE_UNSCHEDULED; -- g_rec_mutex_unlock (&self->priv->lock); --} -- --static void - goa_alarm_dispose (GObject *object) - { - GoaAlarm *self = GOA_ALARM (object); - -- g_clear_object (&self->priv->cancellable); -+ g_clear_object (&self->priv->stream); -+ g_clear_pointer (&self->priv->immediate_wakeup_source, (GDestroyNotify) g_source_destroy); -+ g_clear_pointer (&self->priv->scheduled_wakeup_source, (GDestroyNotify) g_source_destroy); - g_clear_pointer (&self->priv->context, (GDestroyNotify) g_main_context_unref); - g_clear_pointer (&self->priv->time, (GDestroyNotify) g_date_time_unref); -+ g_clear_pointer (&self->priv->previous_wakeup_time, (GDestroyNotify) g_date_time_unref); - - G_OBJECT_CLASS (goa_alarm_parent_class)->dispose (object); - } - - static void - goa_alarm_finalize (GObject *object) - { - GoaAlarm *self = GOA_ALARM (object); - -- clear_scheduled_wakeups (self, self->priv->scheduled_wakeup_source, self->priv->stream); -- - g_rec_mutex_clear (&self->priv->lock); - - G_OBJECT_CLASS (goa_alarm_parent_class)->finalize (object); - } - - static void - goa_alarm_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *param_spec) - { - GoaAlarm *self = GOA_ALARM (object); - GDateTime *time; - - switch (property_id) - { - case PROP_TIME: - time = (GDateTime *) g_value_get_boxed (value); -- goa_alarm_set_time (self, time, self->priv->cancellable); -+ goa_alarm_set_time (self, time); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec); - break; - } - } - - static void - goa_alarm_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *param_spec) - { - GoaAlarm *self = GOA_ALARM (object); - - switch (property_id) - { - case PROP_TIME: - g_value_set_boxed (value, self->priv->time); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec); - break; - } - } - - static void - goa_alarm_class_init (GoaAlarmClass *klass) - { - GObjectClass *object_class; -@@ -198,108 +157,63 @@ goa_alarm_class_init (GoaAlarmClass *klass) - object_class->dispose = goa_alarm_dispose; - object_class->finalize = goa_alarm_finalize; - object_class->get_property = goa_alarm_get_property; - object_class->set_property = goa_alarm_set_property; - - g_type_class_add_private (klass, sizeof (GoaAlarmPrivate)); - - signals[FIRED] = g_signal_new ("fired", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, NULL, NULL, NULL, G_TYPE_NONE, 0); - - signals[REARMED] = g_signal_new ("rearmed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, NULL, NULL, NULL, G_TYPE_NONE, 0); - - g_object_class_install_property (object_class, - PROP_TIME, - g_param_spec_boxed ("time", - _("Time"), - _("Time to fire"), - G_TYPE_DATE_TIME, - G_PARAM_READWRITE)); - } - - static void - goa_alarm_init (GoaAlarm *self) - { - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GOA_TYPE_ALARM, GoaAlarmPrivate); -- self->priv->type = GOA_ALARM_TYPE_UNSCHEDULED; - g_rec_mutex_init (&self->priv->lock); - } - --static gboolean --async_alarm_cancel_idle_cb (gpointer user_data) --{ -- GoaAlarm *self; -- GInputStream *stream; -- GSource *source; -- GTask *task = G_TASK (user_data); -- gpointer task_data; -- -- self = g_task_get_source_object (task); -- source = (GSource *) g_object_get_data (G_OBJECT (task), "alarm-scheduled-wakeup-source"); -- task_data = g_object_get_data (G_OBJECT (task), "alarm-stream"); -- stream = (task_data == NULL) ? NULL : G_INPUT_STREAM (task_data); -- -- clear_scheduled_wakeups (self, source, stream); -- return G_SOURCE_REMOVE; --} -- --static void --on_cancelled (GCancellable *cancellable, gpointer user_data) --{ -- GoaAlarm *self = GOA_ALARM (user_data); -- GSource *idle_source; -- GTask *task; -- -- task = g_task_new (self, NULL, NULL, NULL); -- -- g_object_set_data_full (G_OBJECT (task), -- "alarm-scheduled-wakeup-source", -- g_source_ref (self->priv->scheduled_wakeup_source), -- (GDestroyNotify) g_source_unref); -- -- if (self->priv->stream != NULL) -- g_object_set_data_full (G_OBJECT (task), "alarm-stream", g_object_ref (self->priv->stream), g_object_unref); -- -- idle_source = g_idle_source_new (); -- g_source_set_priority (idle_source, G_PRIORITY_HIGH_IDLE); -- g_source_set_callback (idle_source, async_alarm_cancel_idle_cb, g_object_ref (task), g_object_unref); -- g_source_attach (idle_source, self->priv->context); -- g_source_unref (idle_source); -- -- g_object_unref (task); --} -- - static void - fire_alarm (GoaAlarm *self) - { - g_signal_emit (G_OBJECT (self), signals[FIRED], 0); - } - - static void - rearm_alarm (GoaAlarm *self) - { - g_signal_emit (G_OBJECT (self), signals[REARMED], 0); - } - - static void - fire_or_rearm_alarm (GoaAlarm *self) - { - GTimeSpan time_until_fire; - GTimeSpan previous_time_until_fire; - GDateTime *now; - - now = g_date_time_new_now_local (); - time_until_fire = g_date_time_difference (self->priv->time, now); - - if (self->priv->previous_wakeup_time == NULL) - { - self->priv->previous_wakeup_time = now; - - /* If, according to the time, we're past when we should have fired, - * then fire the alarm. - */ - if (time_until_fire <= 0) -@@ -314,335 +228,282 @@ fire_or_rearm_alarm (GoaAlarm *self) - g_date_time_unref (self->priv->previous_wakeup_time); - self->priv->previous_wakeup_time = now; - - /* If, according to the time, we're past when we should have fired, - * and this is the first wakeup where that's been true then fire - * the alarm. The first check makes sure we don't fire prematurely, - * and the second check makes sure we don't fire more than once - */ - if (time_until_fire <= 0 && previous_time_until_fire > 0) - { - fire_alarm (self); - - /* If, according to the time, we're before when we should fire, - * and we previously fired the alarm, then we've jumped back in - * time and need to rearm the alarm. - */ - } - else if (time_until_fire > 0 && previous_time_until_fire <= 0) - { - rearm_alarm (self); - } - } - } - - static gboolean - on_immediate_wakeup_source_ready (GoaAlarm *self) - { - g_return_val_if_fail (self->priv->type != GOA_ALARM_TYPE_UNSCHEDULED, FALSE); - - g_rec_mutex_lock (&self->priv->lock); -- if (g_cancellable_is_cancelled (self->priv->cancellable)) -- goto out; -- - fire_or_rearm_alarm (self); -- --out: - g_rec_mutex_unlock (&self->priv->lock); - return FALSE; - } - - #ifdef HAVE_TIMERFD - static gboolean --on_timer_source_ready (GObject *stream, GTask *task) -+on_timer_source_ready (GObject *stream, GoaAlarm *self) - { - gint64 number_of_fires; - gssize bytes_read; - gboolean run_again = FALSE; - GError *error = NULL; -- GoaAlarm *self; -- GCancellable *cancellable; -- -- self = g_task_get_source_object (task); -- cancellable = g_task_get_cancellable (task); - - g_return_val_if_fail (GOA_IS_ALARM (self), FALSE); - - g_rec_mutex_lock (&self->priv->lock); - -- if (self->priv->type == GOA_ALARM_TYPE_UNSCHEDULED) -- { -- goa_debug ("GoaAlarm: timer source was unscheduled after " -- "callback was invoked, but before callback got " -- "the lock."); -- goto out; -- } -- else if (self->priv->type != GOA_ALARM_TYPE_TIMER) -+ if (self->priv->type != GOA_ALARM_TYPE_TIMER) - { - goa_warning ("GoaAlarm: timer source ready callback called " - "when timer source isn't supposed to be used. " - "Current timer type is %u", self->priv->type); - goto out; - } - -- if (g_cancellable_is_cancelled (cancellable)) -- goto out; -- - bytes_read = - g_pollable_input_stream_read_nonblocking (G_POLLABLE_INPUT_STREAM (stream), - &number_of_fires, sizeof (gint64), - NULL, &error); - - if (bytes_read < 0) - { - goa_warning ("GoaAlarm: failed to read from timer fd: %s\n", - error->message); - g_error_free (error); - goto out; - } - - if (bytes_read == sizeof (gint64)) - { - if (number_of_fires < 0 || number_of_fires > 1) - { - goa_warning ("GoaAlarm: expected timerfd to report firing once," - "but it reported firing %ld times\n", (long) number_of_fires); - } - } - - fire_or_rearm_alarm (self); - run_again = TRUE; - out: - g_rec_mutex_unlock (&self->priv->lock); - return run_again; - } - #endif - - static gboolean - schedule_wakeups_with_timerfd (GoaAlarm *self) - { - #ifdef HAVE_TIMERFD - struct itimerspec timer_spec; - int fd; - int result; - GSource *source; -- GTask *task; - static gboolean seen_before = FALSE; - - if (!seen_before) - { - goa_debug ("GoaAlarm: trying to use kernel timer"); - seen_before = TRUE; - } - - fd = timerfd_create (CLOCK_REALTIME, TFD_CLOEXEC | TFD_NONBLOCK); - - if (fd < 0) - { - goa_debug ("GoaAlarm: could not create timer fd: %m"); - return FALSE; - } - - memset (&timer_spec, 0, sizeof (timer_spec)); - timer_spec.it_value.tv_sec = g_date_time_to_unix (self->priv->time) + 1; - - result = timerfd_settime (fd, - TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, - &timer_spec, NULL); - - if (result < 0) - { - goa_debug ("GoaAlarm: could not set timer: %m"); - return FALSE; - } - - self->priv->type = GOA_ALARM_TYPE_TIMER; - self->priv->stream = g_unix_input_stream_new (fd, TRUE); - -- task = g_task_new (self, self->priv->cancellable, NULL, NULL); -- - source = - g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM - (self->priv->stream), -- self->priv->cancellable); -+ NULL); - self->priv->scheduled_wakeup_source = source; - g_source_set_callback (self->priv->scheduled_wakeup_source, -- (GSourceFunc) on_timer_source_ready, task, -- (GDestroyNotify) g_object_unref); -+ (GSourceFunc) on_timer_source_ready, self, -+ (GDestroyNotify) clear_wakeup_source_pointer); - g_source_attach (self->priv->scheduled_wakeup_source, self->priv->context); - g_source_unref (source); - - return TRUE; - - #endif /*HAVE_TIMERFD */ - - return FALSE; - } - - static gboolean - on_timeout_source_ready (GoaAlarm *self) - { - g_return_val_if_fail (GOA_IS_ALARM (self), FALSE); - - g_rec_mutex_lock (&self->priv->lock); - -- if (g_cancellable_is_cancelled (self->priv->cancellable) || -- self->priv->type == GOA_ALARM_TYPE_UNSCHEDULED) -+ if (self->priv->type == GOA_ALARM_TYPE_UNSCHEDULED) - goto out; - - fire_or_rearm_alarm (self); - -- if (g_cancellable_is_cancelled (self->priv->cancellable)) -- goto out; -- - schedule_wakeups_with_timeout_source (self); - - out: - g_rec_mutex_unlock (&self->priv->lock); - return FALSE; - } - - static void --clear_timeout_source_pointer (GoaAlarm *self) -+clear_wakeup_source_pointer (GoaAlarm *self) - { - self->priv->scheduled_wakeup_source = NULL; - } - - static void - schedule_wakeups_with_timeout_source (GoaAlarm *self) - { - GDateTime *now; - GSource *source; - GTimeSpan time_span; - guint interval; - - self->priv->type = GOA_ALARM_TYPE_TIMEOUT; - - now = g_date_time_new_now_local (); - time_span = g_date_time_difference (self->priv->time, now); - g_date_time_unref (now); - - time_span = - CLAMP (time_span, 1000 *G_TIME_SPAN_MILLISECOND, - G_MAXUINT *G_TIME_SPAN_MILLISECOND); - interval = (guint) time_span / G_TIME_SPAN_MILLISECOND; - - /* We poll every 10 seconds or so because we want to catch time skew - */ - interval = MIN (interval, MAX_TIMEOUT_INTERVAL); - - source = g_timeout_source_new (interval); - - self->priv->scheduled_wakeup_source = source; - g_source_set_callback (self->priv->scheduled_wakeup_source, - (GSourceFunc) - on_timeout_source_ready, -- self, (GDestroyNotify) clear_timeout_source_pointer); -+ self, (GDestroyNotify) clear_wakeup_source_pointer); - - g_source_attach (self->priv->scheduled_wakeup_source, self->priv->context); - g_source_unref (source); - } - - static void - schedule_wakeups (GoaAlarm *self) - { - gboolean wakeup_scheduled; - - wakeup_scheduled = schedule_wakeups_with_timerfd (self); - - if (!wakeup_scheduled) - { - static gboolean seen_before = FALSE; - - if (!seen_before) - { - goa_debug ("GoaAlarm: falling back to polling timeout"); - seen_before = TRUE; - } - schedule_wakeups_with_timeout_source (self); - } - } - - static void - clear_immediate_wakeup_source_pointer (GoaAlarm *self) - { - self->priv->immediate_wakeup_source = NULL; - } - - static void - schedule_immediate_wakeup (GoaAlarm *self) - { - GSource *source; - - source = g_idle_source_new (); - - self->priv->immediate_wakeup_source = source; - g_source_set_callback (self->priv->immediate_wakeup_source, - (GSourceFunc) - on_immediate_wakeup_source_ready, - self, - (GDestroyNotify) clear_immediate_wakeup_source_pointer); - - g_source_attach (self->priv->immediate_wakeup_source, self->priv->context); - g_source_unref (source); - } - --void --goa_alarm_set_time (GoaAlarm *self, GDateTime *time, GCancellable *cancellable) -+static void -+goa_alarm_set_time (GoaAlarm *self, GDateTime *time) - { -- if (g_cancellable_is_cancelled (cancellable)) -- return; -- - g_rec_mutex_lock (&self->priv->lock); -- if (self->priv->cancellable != NULL && self->priv->cancellable != cancellable) -- g_cancellable_cancel (self->priv->cancellable); -- -- if (cancellable != NULL) -- g_object_ref (cancellable); -- -- if (self->priv->cancelled_id != 0) -- g_cancellable_disconnect (self->priv->cancellable, self->priv->cancelled_id); -- -- g_clear_object (&self->priv->cancellable); -- -- if (cancellable != NULL) -- self->priv->cancellable = cancellable; -- else -- self->priv->cancellable = g_cancellable_new (); -- -- self->priv->cancelled_id = g_cancellable_connect (self->priv->cancellable, -- G_CALLBACK (on_cancelled), -- self, NULL); - - g_date_time_ref (time); -- -- if (self->priv->time != NULL) -- g_date_time_unref (self->priv->time); -- - self->priv->time = time; - - if (self->priv->context == NULL) - self->priv->context = g_main_context_ref (g_main_context_default ()); - - schedule_wakeups (self); - - /* Wake up right away, in case it's already expired leaving the gate */ - schedule_immediate_wakeup (self); - g_rec_mutex_unlock (&self->priv->lock); - g_object_notify (G_OBJECT (self), "time"); - } - - GDateTime * - goa_alarm_get_time (GoaAlarm *self) - { - return self->priv->time; - } - - GoaAlarm * --goa_alarm_new (void) -+goa_alarm_new (GDateTime *alarm_time) - { - GoaAlarm *self; - -- self = GOA_ALARM (g_object_new (GOA_TYPE_ALARM, NULL)); -+ self = GOA_ALARM (g_object_new (GOA_TYPE_ALARM, "time", alarm_time, NULL)); - - return GOA_ALARM (self); - } -diff --git a/src/goaidentity/goaalarm.h b/src/goaidentity/goaalarm.h -index a93991d..75252a4 100644 ---- a/src/goaidentity/goaalarm.h -+++ b/src/goaidentity/goaalarm.h -@@ -28,37 +28,34 @@ - #include - - G_BEGIN_DECLS - #define GOA_TYPE_ALARM (goa_alarm_get_type ()) - #define GOA_ALARM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GOA_TYPE_ALARM, GoaAlarm)) - #define GOA_ALARM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GOA_TYPE_ALARM, GoaAlarmClass)) - #define GOA_IS_ALARM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GOA_TYPE_ALARM)) - #define GOA_IS_ALARM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GOA_TYPE_ALARM)) - #define GOA_ALARM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GOA_TYPE_ALARM, GoaAlarmClass)) - typedef struct _GoaAlarm GoaAlarm; - typedef struct _GoaAlarmClass GoaAlarmClass; - typedef struct _GoaAlarmPrivate GoaAlarmPrivate; - - struct _GoaAlarm - { - GObject parent; - - GoaAlarmPrivate *priv; - }; - - struct _GoaAlarmClass - { - GObjectClass parent_class; - - void (* fired) (GoaAlarm *alarm); - void (* rearmed) (GoaAlarm *alarm); - }; - - GType goa_alarm_get_type (void); - --GoaAlarm *goa_alarm_new (void); --void goa_alarm_set_time (GoaAlarm *alarm, -- GDateTime *time, -- GCancellable *cancellable); -+GoaAlarm *goa_alarm_new (GDateTime *time); - GDateTime *goa_alarm_get_time (GoaAlarm *alarm); - G_END_DECLS - #endif /* __GOA_ALARM_H__ */ -diff --git a/src/goaidentity/goakerberosidentity.c b/src/goaidentity/goakerberosidentity.c -index f06bf30..c3a65f6 100644 ---- a/src/goaidentity/goakerberosidentity.c -+++ b/src/goaidentity/goakerberosidentity.c -@@ -29,121 +29,114 @@ - #include "goalogging.h" - - #include - #include - #include - - #include - #include - #include - - typedef enum - { - VERIFICATION_LEVEL_UNVERIFIED, - VERIFICATION_LEVEL_ERROR, - VERIFICATION_LEVEL_EXISTS, - VERIFICATION_LEVEL_SIGNED_IN - } VerificationLevel; - - struct _GoaKerberosIdentityPrivate - { - krb5_context kerberos_context; - krb5_ccache credentials_cache; - - char *identifier; - guint identifier_idle_id; - - krb5_timestamp expiration_time; - guint expiration_time_idle_id; - - GoaAlarm *expiration_alarm; -- GCancellable *expiration_alarm_cancellable; -- - GoaAlarm *expiring_alarm; -- GCancellable *expiring_alarm_cancellable; -- - GoaAlarm *renewal_alarm; -- GCancellable *renewal_alarm_cancellable; - - VerificationLevel cached_verification_level; - guint is_signed_in_idle_id; - }; - - enum - { - EXPIRING, - EXPIRED, - UNEXPIRED, - NEEDS_RENEWAL, - NEEDS_REFRESH, - NUMBER_OF_SIGNALS, - }; - - enum - { - PROP_0, - PROP_IDENTIFIER, - PROP_IS_SIGNED_IN, - PROP_EXPIRATION_TIMESTAMP - }; - - static guint signals[NUMBER_OF_SIGNALS] = { 0 }; - - static void identity_interface_init (GoaIdentityInterface *interface); - static void initable_interface_init (GInitableIface *interface); - static void reset_alarms (GoaKerberosIdentity *self); - static void clear_alarms (GoaKerberosIdentity *self); - static gboolean goa_kerberos_identity_is_signed_in (GoaIdentity *identity); - static void set_error_from_krb5_error_code (GoaKerberosIdentity *self, - GError **error, - gint code, - krb5_error_code error_code, - const char *format, - ...); - - G_LOCK_DEFINE_STATIC (identity_lock); - - G_DEFINE_TYPE_WITH_CODE (GoaKerberosIdentity, - goa_kerberos_identity, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, - initable_interface_init) - G_IMPLEMENT_INTERFACE (GOA_TYPE_IDENTITY, - identity_interface_init)); - static void - goa_kerberos_identity_dispose (GObject *object) - { - GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (object); - - G_LOCK (identity_lock); -- clear_alarms (self); -- - g_clear_object (&self->priv->renewal_alarm); - g_clear_object (&self->priv->expiring_alarm); - g_clear_object (&self->priv->expiration_alarm); - G_UNLOCK (identity_lock); - - G_OBJECT_CLASS (goa_kerberos_identity_parent_class)->dispose (object); - - } - - static void - goa_kerberos_identity_finalize (GObject *object) - { - GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (object); - - g_free (self->priv->identifier); - - if (self->priv->credentials_cache != NULL) - krb5_cc_close (self->priv->kerberos_context, self->priv->credentials_cache); - - G_OBJECT_CLASS (goa_kerberos_identity_parent_class)->finalize (object); - } - - static void - goa_kerberos_identity_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *param_spec) - { - GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (object); - -@@ -279,63 +272,60 @@ get_identifier (GoaKerberosIdentity *self, - principal, - 0, - &unparsed_name); - - if (error_code != 0) - { - const char *error_message; - - error_message = - krb5_get_error_message (self->priv->kerberos_context, error_code); - goa_debug ("GoaKerberosIdentity: Error parsing principal identity name: %s", - error_message); - krb5_free_error_message (self->priv->kerberos_context, error_message); - goto out; - } - - identifier = g_strdup (unparsed_name); - krb5_free_unparsed_name (self->priv->kerberos_context, unparsed_name); - - out: - krb5_free_principal (self->priv->kerberos_context, principal); - return identifier; - } - - static void - goa_kerberos_identity_init (GoaKerberosIdentity *self) - { - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - GOA_TYPE_KERBEROS_IDENTITY, - GoaKerberosIdentityPrivate); -- self->priv->expiration_alarm = goa_alarm_new (); -- self->priv->expiring_alarm = goa_alarm_new (); -- self->priv->renewal_alarm = goa_alarm_new (); - } - - static void - set_error_from_krb5_error_code (GoaKerberosIdentity *self, - GError **error, - gint code, - krb5_error_code error_code, - const char *format, - ...) - { - const char *error_message; - char *literal_message; - char *expanded_format; - va_list args; - char **chunks; - - error_message = krb5_get_error_message (self->priv->kerberos_context, error_code); - chunks = g_strsplit (format, "%k", -1); - expanded_format = g_strjoinv (error_message, chunks); - g_strfreev (chunks); - krb5_free_error_message (self->priv->kerberos_context, error_message); - - va_start (args, format); - literal_message = g_strdup_vprintf (expanded_format, args); - va_end (args); - - g_set_error_literal (error, GOA_IDENTITY_ERROR, code, literal_message); - g_free (literal_message); - } - -@@ -714,230 +704,233 @@ on_expiration_alarm_fired (GoaAlarm *alarm, - } - - static void - on_expiration_alarm_rearmed (GoaAlarm *alarm, - GoaKerberosIdentity *self) - { - g_return_if_fail (GOA_IS_ALARM (alarm)); - g_return_if_fail (GOA_IS_KERBEROS_IDENTITY (self)); - - goa_debug ("GoaKerberosIdentity: expiration alarm rearmed"); - g_signal_emit (G_OBJECT (self), signals[NEEDS_REFRESH], 0); - } - - static void - on_renewal_alarm_rearmed (GoaAlarm *alarm, - GoaKerberosIdentity *self) - { - g_return_if_fail (GOA_IS_ALARM (alarm)); - g_return_if_fail (GOA_IS_KERBEROS_IDENTITY (self)); - - goa_debug ("GoaKerberosIdentity: renewal alarm rearmed"); - } - - static void - on_renewal_alarm_fired (GoaAlarm *alarm, - GoaKerberosIdentity *self) - { - g_return_if_fail (GOA_IS_ALARM (alarm)); - g_return_if_fail (GOA_IS_KERBEROS_IDENTITY (self)); - -- g_clear_object (&self->priv->renewal_alarm_cancellable); -- - if (self->priv->cached_verification_level == VERIFICATION_LEVEL_SIGNED_IN) - { - goa_debug ("GoaKerberosIdentity: renewal alarm fired for signed-in identity"); - g_signal_emit (G_OBJECT (self), signals[NEEDS_RENEWAL], 0); - } - } - - static void - on_expiring_alarm_rearmed (GoaAlarm *alarm, - GoaKerberosIdentity *self) - { - g_return_if_fail (GOA_IS_ALARM (alarm)); - g_return_if_fail (GOA_IS_KERBEROS_IDENTITY (self)); - - goa_debug ("GoaKerberosIdentity: expiring alarm rearmed"); - } - - static void - on_expiring_alarm_fired (GoaAlarm *alarm, - GoaKerberosIdentity *self) - { - g_return_if_fail (GOA_IS_ALARM (alarm)); - g_return_if_fail (GOA_IS_KERBEROS_IDENTITY (self)); - -- g_clear_object (&self->priv->expiring_alarm_cancellable); -- - if (self->priv->cached_verification_level == VERIFICATION_LEVEL_SIGNED_IN) - { - goa_debug ("GoaKerberosIdentity: expiring alarm fired for signed-in identity"); - g_signal_emit (G_OBJECT (self), signals[EXPIRING], 0); - } - } - -+static gboolean -+unref_alarm (GoaAlarm *alarm) -+{ -+ g_object_unref (G_OBJECT (alarm)); -+ return G_SOURCE_REMOVE; -+} -+ - static void --set_alarm (GoaKerberosIdentity *self, -- GoaAlarm *alarm, -- GDateTime *alarm_time, -- GCancellable **cancellable) -+clear_alarm_and_unref_on_idle (GoaKerberosIdentity *self, -+ GoaAlarm **alarm) - { -- GDateTime *old_alarm_time; -+ if (!*alarm) -+ return; -+ -+ g_idle_add ((GSourceFunc) unref_alarm, *alarm); -+ *alarm = NULL; -+} -+ -+static void -+reset_alarm (GoaKerberosIdentity *self, -+ GoaAlarm **alarm, -+ GDateTime *alarm_time) -+{ -+ GDateTime *old_alarm_time = NULL; - - G_LOCK (identity_lock); -- old_alarm_time = goa_alarm_get_time (alarm); -+ if (*alarm) -+ old_alarm_time = goa_alarm_get_time (*alarm); - if (old_alarm_time == NULL || !g_date_time_equal (alarm_time, old_alarm_time)) - { -- GCancellable *new_cancellable; -- -- new_cancellable = g_cancellable_new (); -- goa_alarm_set_time (alarm, alarm_time, new_cancellable); -- -- g_clear_object (cancellable); -- *cancellable = new_cancellable; -+ clear_alarm_and_unref_on_idle (self, alarm); -+ *alarm = goa_alarm_new (alarm_time); - } - G_UNLOCK (identity_lock); - - } - - static void - disconnect_alarm_signals (GoaKerberosIdentity *self) - { -- g_signal_handlers_disconnect_by_func (G_OBJECT (self->priv->renewal_alarm), -- G_CALLBACK (on_renewal_alarm_fired), -- self); -- g_signal_handlers_disconnect_by_func (G_OBJECT (self->priv->renewal_alarm), -- G_CALLBACK (on_renewal_alarm_rearmed), -- self); -- g_signal_handlers_disconnect_by_func (G_OBJECT (self->priv->expiring_alarm), -- G_CALLBACK (on_expiring_alarm_fired), -- self); -- g_signal_handlers_disconnect_by_func (G_OBJECT (self->priv->expiration_alarm), -- G_CALLBACK (on_expiration_alarm_rearmed), -- self); -- g_signal_handlers_disconnect_by_func (G_OBJECT (self->priv->expiration_alarm), -- G_CALLBACK (on_expiration_alarm_fired), -- self); -- g_signal_handlers_disconnect_by_func (G_OBJECT (self->priv->expiring_alarm), -- G_CALLBACK (on_expiring_alarm_rearmed), -- self); -+ if (self->priv->renewal_alarm) -+ { -+ g_signal_handlers_disconnect_by_func (G_OBJECT (self->priv->renewal_alarm), -+ G_CALLBACK (on_renewal_alarm_fired), -+ self); -+ g_signal_handlers_disconnect_by_func (G_OBJECT (self->priv->renewal_alarm), -+ G_CALLBACK (on_renewal_alarm_rearmed), -+ self); -+ } -+ -+ if (self->priv->expiring_alarm) -+ { -+ g_signal_handlers_disconnect_by_func (G_OBJECT (self->priv->expiring_alarm), -+ G_CALLBACK (on_expiring_alarm_fired), -+ self); -+ g_signal_handlers_disconnect_by_func (G_OBJECT (self->priv->expiring_alarm), -+ G_CALLBACK (on_expiring_alarm_rearmed), -+ self); -+ } -+ -+ if (self->priv->expiration_alarm) -+ { -+ g_signal_handlers_disconnect_by_func (G_OBJECT (self->priv->expiration_alarm), -+ G_CALLBACK (on_expiration_alarm_rearmed), -+ self); -+ g_signal_handlers_disconnect_by_func (G_OBJECT (self->priv->expiration_alarm), -+ G_CALLBACK (on_expiration_alarm_fired), -+ self); -+ } - } - - static void - connect_alarm_signals (GoaKerberosIdentity *self) - { - g_signal_connect (G_OBJECT (self->priv->renewal_alarm), - "fired", - G_CALLBACK (on_renewal_alarm_fired), - self); - g_signal_connect (G_OBJECT (self->priv->renewal_alarm), - "rearmed", - G_CALLBACK (on_renewal_alarm_rearmed), - self); - g_signal_connect (G_OBJECT (self->priv->expiring_alarm), - "fired", - G_CALLBACK (on_expiring_alarm_fired), - self); - g_signal_connect (G_OBJECT (self->priv->expiring_alarm), - "rearmed", - G_CALLBACK (on_expiring_alarm_rearmed), - self); - g_signal_connect (G_OBJECT (self->priv->expiration_alarm), - "fired", - G_CALLBACK (on_expiration_alarm_fired), - self); - g_signal_connect (G_OBJECT (self->priv->expiration_alarm), - "rearmed", - G_CALLBACK (on_expiration_alarm_rearmed), - self); - } - - static void - reset_alarms (GoaKerberosIdentity *self) - { - GDateTime *now; - GDateTime *expiration_time; - GDateTime *expiring_time; - GDateTime *renewal_time; - GTimeSpan time_span_until_expiration; - - now = g_date_time_new_now_local (); - expiration_time = g_date_time_new_from_unix_local (self->priv->expiration_time); - time_span_until_expiration = g_date_time_difference (expiration_time, now); - g_date_time_unref (now); - - /* Let the user reauthenticate 10 min before expiration */ - expiring_time = g_date_time_add_minutes (expiration_time, -10); - - /* Try to quietly auto-renew halfway through so in ideal configurations - * the ticket is never more than halfway to expired - */ - renewal_time = g_date_time_add (expiration_time, - -(time_span_until_expiration / 2)); - - disconnect_alarm_signals (self); - -- set_alarm (self, -- self->priv->renewal_alarm, -- renewal_time, &self->priv->renewal_alarm_cancellable); -- set_alarm (self, -- self->priv->expiring_alarm, -- expiring_time, &self->priv->expiring_alarm_cancellable); -- set_alarm (self, -- self->priv->expiration_alarm, -- expiration_time, &self->priv->expiration_alarm_cancellable); -+ reset_alarm (self, &self->priv->renewal_alarm, renewal_time); -+ reset_alarm (self, &self->priv->expiring_alarm, expiring_time); -+ reset_alarm (self, &self->priv->expiration_alarm, expiration_time); - - g_date_time_unref (renewal_time); - g_date_time_unref (expiring_time); - g_date_time_unref (expiration_time); - connect_alarm_signals (self); - } - - static void --cancel_and_clear_cancellable (GCancellable **cancellable) --{ -- if (cancellable == NULL) -- return; -- -- if (!g_cancellable_is_cancelled (*cancellable)) -- g_cancellable_cancel (*cancellable); -- -- g_clear_object (cancellable); --} -- --static void - clear_alarms (GoaKerberosIdentity *self) - { -- cancel_and_clear_cancellable (&self->priv->renewal_alarm_cancellable); -- cancel_and_clear_cancellable (&self->priv->expiring_alarm_cancellable); -- cancel_and_clear_cancellable (&self->priv->expiration_alarm_cancellable); -+ disconnect_alarm_signals (self); -+ clear_alarm_and_unref_on_idle (self, &self->priv->renewal_alarm); -+ clear_alarm_and_unref_on_idle (self, &self->priv->expiring_alarm); -+ clear_alarm_and_unref_on_idle (self, &self->priv->expiration_alarm); - } - - static gboolean - goa_kerberos_identity_initable_init (GInitable *initable, - GCancellable *cancellable, - GError **error) - { - GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (initable); - GError *verification_error; - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - return FALSE; - - if (self->priv->identifier == NULL) - { - self->priv->identifier = get_identifier (self, error); - - if (self->priv->identifier != NULL) - queue_notify (self, &self->priv->identifier_idle_id, "identifier"); - } - - verification_error = NULL; - self->priv->cached_verification_level = - verify_identity (self, &verification_error); - - switch (self->priv->cached_verification_level) - { - case VERIFICATION_LEVEL_EXISTS: - case VERIFICATION_LEVEL_SIGNED_IN: - reset_alarms (self); --- -1.8.3.1 - - -From cf3bffb0e0a5eb2e5e37709956de70a48f12eb83 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Fri, 9 May 2014 09:11:13 -0400 -Subject: [PATCH 23/24] goaidentity: don't leak credentials caches - -krb5_cc_default doesn't return a shared resource, and -the results need to be freed. Likewise, -get_new_credentials_cache needs to be freed. - -https://bugzilla.gnome.org/show_bug.cgi?id=729874 ---- - src/goaidentity/goakerberosidentitymanager.c | 33 ++++++++++++---------------- - 1 file changed, 14 insertions(+), 19 deletions(-) - -diff --git a/src/goaidentity/goakerberosidentitymanager.c b/src/goaidentity/goakerberosidentitymanager.c -index 5e33003..7cc90b9 100644 ---- a/src/goaidentity/goakerberosidentitymanager.c -+++ b/src/goaidentity/goakerberosidentitymanager.c -@@ -767,127 +767,120 @@ get_new_credentials_cache (GoaKerberosIdentityManager *self, - - if (g_strcmp0 (self->priv->credentials_cache_type, "FILE") == 0) - { - goa_debug ("GoaKerberosIdentityManager: credential cache type %s doesn't supports cache collections", self->priv->credentials_cache_type); - supports_multiple_identities = FALSE; - } - else if (g_strcmp0 (self->priv->credentials_cache_type, "DIR") == 0 || - g_strcmp0 (self->priv->credentials_cache_type, "KEYRING") == 0) - { - goa_debug ("GoaKerberosIdentityManager: credential cache type %s supports cache collections", self->priv->credentials_cache_type); - supports_multiple_identities = TRUE; - } - else - { - goa_debug ("GoaKerberosIdentityManager: don't know if credential cache type %s supports cache collections, assuming yes", self->priv->credentials_cache_type); - supports_multiple_identities = TRUE; - } - - /* If we're configured for FILE based credentials, then we only - * have one ccache, and we need to use it always. - * - * If we're configured for DIR or KEYRING based credentials, then we - * can have multiple ccache's so we should use the default one first - * (so it gets selected automatically) and then fallback to unique - * ccache names for subsequent tickets. - * - */ - if (!supports_multiple_identities || - g_hash_table_size (self->priv->identities) == 0) - { -- krb5_ccache default_cache; -- -- error_code = krb5_cc_default (self->priv->kerberos_context, &default_cache); -- -- if (error_code == 0) -- krb5_cc_dup (self->priv->kerberos_context, default_cache, credentials_cache); -+ error_code = krb5_cc_default (self->priv->kerberos_context, credentials_cache); - } - else - { - error_code = krb5_cc_new_unique (self->priv->kerberos_context, - self->priv->credentials_cache_type, - NULL, - credentials_cache); - } - - return error_code; - } - - static void - sign_in_identity (GoaKerberosIdentityManager *self, - Operation *operation) - { - GoaIdentity *identity; - GError *error; - krb5_error_code error_code; - - goa_debug ("GoaKerberosIdentityManager: signing in identity %s", - operation->identifier); - error = NULL; - identity = g_hash_table_lookup (self->priv->identities, operation->identifier); - if (identity == NULL) - { - krb5_ccache credentials_cache; - - error_code = get_new_credentials_cache (self, &credentials_cache); - - if (error_code != 0) - { - const char *error_message; - - error_message = - krb5_get_error_message (self->priv->kerberos_context, error_code); - goa_debug ("GoaKerberosIdentityManager: Error creating new cache for identity credentials: %s", - error_message); - krb5_free_error_message (self->priv->kerberos_context, error_message); - - g_simple_async_result_set_error (operation->result, - GOA_IDENTITY_MANAGER_ERROR, - GOA_IDENTITY_MANAGER_ERROR_CREATING_IDENTITY, - _("Could not create credential cache for identity")); - g_simple_async_result_set_op_res_gpointer (operation->result, NULL, NULL); - return; - } -- else -+ -+ identity = goa_kerberos_identity_new (self->priv->kerberos_context, -+ credentials_cache, -+ &error); -+ krb5_cc_close (self->priv->kerberos_context, credentials_cache); -+ if (identity == NULL) - { -- identity = goa_kerberos_identity_new (self->priv->kerberos_context, -- credentials_cache, -- &error); -- if (identity == NULL) -- { -- krb5_cc_close (self->priv->kerberos_context, credentials_cache); -- g_simple_async_result_take_error (operation->result, error); -- g_simple_async_result_set_op_res_gpointer (operation->result, -- NULL, -- NULL); -- return; -- } -+ g_simple_async_result_take_error (operation->result, error); -+ g_simple_async_result_set_op_res_gpointer (operation->result, -+ NULL, -+ NULL); -+ return; - } - } - else - { - g_object_ref (identity); - } - - g_hash_table_replace (self->priv->identities, - g_strdup (operation->identifier), - g_object_ref (identity)); - - if (!goa_kerberos_identity_sign_in (GOA_KERBEROS_IDENTITY (identity), - operation->identifier, - operation->initial_password, - operation->sign_in_flags, - (GoaIdentityInquiryFunc) - on_kerberos_identity_inquiry, - operation, - NULL, - operation->cancellable, - &error)) - { - g_simple_async_result_set_from_error (operation->result, error); - g_simple_async_result_set_op_res_gpointer (operation->result, - NULL, - NULL); - - } - else - { -@@ -1440,60 +1433,62 @@ monitor_credentials_cache (GoaKerberosIdentityManager *self, - &monitoring_error); - g_object_unref (directory); - - } - g_object_unref (file); - } - - if (monitor == NULL) - { - if (monitoring_error != NULL) - { - goa_warning ("GoaKerberosIdentityManager: Could not monitor credentials for %s (type %s), reverting to polling: %s", - cache_path, - cache_type, - monitoring_error != NULL? monitoring_error->message : ""); - g_clear_error (&monitoring_error); - } - can_monitor = FALSE; - } - else - { - self->priv->credentials_cache_changed_signal_id = - g_signal_connect (G_OBJECT (monitor), "changed", - G_CALLBACK (on_credentials_cache_changed), self); - self->priv->credentials_cache_monitor = monitor; - } - - if (!can_monitor) - self->priv->polling_timeout_id = g_timeout_add_seconds (FALLBACK_POLLING_INTERVAL, (GSourceFunc) on_polling_timeout, self); - -+ krb5_cc_close (self->priv->kerberos_context, default_cache); -+ - return TRUE; - } - - static void - stop_watching_credentials_cache (GoaKerberosIdentityManager *self) - { - if (self->priv->credentials_cache_monitor != NULL) - { - if (!g_file_monitor_is_cancelled (self->priv->credentials_cache_monitor)) - g_file_monitor_cancel (self->priv->credentials_cache_monitor); - - g_clear_object (&self->priv->credentials_cache_monitor); - } - - if (self->priv->polling_timeout_id != 0) - { - g_source_remove (self->priv->polling_timeout_id); - self->priv->polling_timeout_id = 0; - } - } - - static gboolean - goa_kerberos_identity_manager_initable_init (GInitable *initable, - GCancellable *cancellable, - GError **error) - { - GoaKerberosIdentityManager *self = GOA_KERBEROS_IDENTITY_MANAGER (initable); - krb5_error_code error_code; - GError *monitoring_error; - --- -1.8.3.1 - -From 097aa719985923fd551c2c68a63ebca3609031ca Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 6 Nov 2013 16:58:43 -0500 -Subject: [PATCH 24/24] kerberos: don't crash if keyring credentials disappear - -It's possible to make gnome-online-accounts crash by: - -1) creating a kerberos account in control-center -2) deleting the stored credentials from gnome keyring using seahorse -3) running kdestroy in the terminal to make the sign in button show up -in the control-center panel -4) clicking sign in - -This is because the provider makes the assumption that there will always -be stored credentials when signing in interactively, which is incorrect -in the above scenario (because of step 2). - -This commit hardens the get_ticket_sync function against credentials -disappearing. - -https://bugzilla.gnome.org/show_bug.cgi?id=711572 ---- - src/goabackend/goakerberosprovider.c | 24 ++++++++++++++---------- - 1 file changed, 14 insertions(+), 10 deletions(-) - -diff --git a/src/goabackend/goakerberosprovider.c b/src/goabackend/goakerberosprovider.c -index e795856..fbe0364 100644 ---- a/src/goabackend/goakerberosprovider.c -+++ b/src/goabackend/goakerberosprovider.c -@@ -668,97 +668,101 @@ look_up_identity (GoaKerberosProvider *self, - operation_result); - } - - static void - on_account_signed_in (GoaProvider *provider, - GAsyncResult *result, - SignInRequest *request) - { - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), - &request->error)) - { - g_main_loop_quit (request->loop); - return; - } - - g_main_loop_quit (request->loop); - } - - static gboolean - get_ticket_sync (GoaKerberosProvider *self, - GoaObject *object, - gboolean is_interactive, - GCancellable *cancellable, - GError **error) - { - GVariant *credentials; - GError *lookup_error; - GoaAccount *account; - const char *identifier; - const char *password; -- gboolean has_password; - SignInRequest request; - gboolean ret; - - ret = FALSE; - - account = goa_object_peek_account (object); - identifier = goa_account_get_identity (account); - password = NULL; - - lookup_error = NULL; - credentials = goa_utils_lookup_credentials_sync (GOA_PROVIDER (self), - object, - cancellable, - &lookup_error); - - if (credentials == NULL && !is_interactive) - { - if (lookup_error != NULL) - g_propagate_error (error, lookup_error); - else - g_set_error (error, - GOA_ERROR, - GOA_ERROR_NOT_AUTHORIZED, - _("Could not find saved credentials for principal `%s' in keyring"), identifier); - goto out; - } -- -- has_password = g_variant_lookup (credentials, "password", "&s", &password); -- if (!has_password && !is_interactive) -+ else if (credentials != NULL) - { -- g_set_error (error, -- GOA_ERROR, -- GOA_ERROR_NOT_AUTHORIZED, -- _("Did not find password for principal `%s' in credentials"), -- identifier); -- goto out; -+ gboolean has_password; -+ -+ has_password = g_variant_lookup (credentials, "password", "&s", &password); -+ -+ if (!has_password && !is_interactive) -+ { -+ g_set_error (error, -+ GOA_ERROR, -+ GOA_ERROR_NOT_AUTHORIZED, -+ _("Did not find password for principal `%s' in credentials"), -+ identifier); -+ goto out; -+ } - } - - 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, - cancellable, - (GAsyncReadyCallback) - on_account_signed_in, - &request); - - g_main_loop_run (request.loop); - g_main_loop_unref (request.loop); - - if (request.error != NULL) - { - g_propagate_error (error, request.error); - goto out; - } - - ret = TRUE; - out: - if (credentials != NULL) - g_variant_unref (credentials); - - return ret; - } --- -1.8.3.1 - diff --git a/SOURCES/kerberos-separate-process.patch b/SOURCES/kerberos-separate-process.patch new file mode 100644 index 0000000..c21a5a9 --- /dev/null +++ b/SOURCES/kerberos-separate-process.patch @@ -0,0 +1,1417 @@ +From a905f21aeef808b3ec7d9a343953551334acdc18 Mon Sep 17 00:00:00 2001 +From: Ray Strode +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 f9c54cd..2eb6b67 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.1.0 + + +From 9dc739548d3cd27df2b9bce46099d14267d6032a Mon Sep 17 00:00:00 2001 +From: Ray Strode +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 cb30eb8..fb68063 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 0000000..bd3b032 +--- /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 9fdb115..8f5352f 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 9d5543d..30016f5 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 8e11f6d..537287a 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 38bbde6..6b6225a 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 0000000..2de35ac +--- /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 . ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++ ++#include ++ ++#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.1.0 + diff --git a/SOURCES/kerberos-smartcard.patch b/SOURCES/kerberos-smartcard.patch new file mode 100644 index 0000000..0660af1 --- /dev/null +++ b/SOURCES/kerberos-smartcard.patch @@ -0,0 +1,589 @@ +From 3753904f1de123a724438bf7f0c58aac00ce4ef4 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Tue, 21 Oct 2014 10:38:17 -0400 +Subject: [PATCH 1/2] ticketing: add new details property + +This commit adds a new "details" variant for attaching metadata +about tickets getting requested via the ticketing interface. + +This will give the kerberos account provider a place to tuck away +kerberos-specific preauthentication configuration for the tickets +associated with smartcard backed kerberos accounts. +--- + data/dbus-interfaces.xml | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/data/dbus-interfaces.xml b/data/dbus-interfaces.xml +index 5bf26e9..fa8b18c 100644 +--- a/data/dbus-interfaces.xml ++++ b/data/dbus-interfaces.xml +@@ -726,6 +726,8 @@ + ticketing capabilities. + --> + ++ ++ +