Add more kerberos fixes from upstream

Related: #2152695
This commit is contained in:
Ray Strode 2023-01-20 09:51:01 -05:00
parent 02d15e5abd
commit 372d6fafed
5 changed files with 4467 additions and 959 deletions

640
112.patch
View File

@ -1,640 +0,0 @@
From c492cbfd861bc773cf8b4c15bc722380355fc4b3 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Mon, 28 Nov 2022 14:16:09 -0500
Subject: [PATCH 1/2] kerberos-identity: Attempt to cope with multiple
credential caches per identity
At the moment the identity service assumes there will just be one
credential cache collection for any given prinicipal.
This isn't necessarily true though, and the service gets quite
confused when that assumption doesn't hold up.
This commit attempts to make it cope with the situation better, by
maintaining a hash table of collections per identity. It deems
one of the collections the "active" one and relegates the rest to
be backup if the active one expires and can't be renewed.
Closes: https://gitlab.gnome.org/GNOME/gnome-online-accounts/-/issues/79
---
src/goaidentity/goakerberosidentity.c | 340 ++++++++++++++++++++++----
1 file changed, 287 insertions(+), 53 deletions(-)
diff --git a/src/goaidentity/goakerberosidentity.c b/src/goaidentity/goakerberosidentity.c
index 695396bf..dbb5991d 100644
--- a/src/goaidentity/goakerberosidentity.c
+++ b/src/goaidentity/goakerberosidentity.c
@@ -33,8 +33,8 @@
typedef enum
{
+ VERIFICATION_LEVEL_ERROR = -1,
VERIFICATION_LEVEL_UNVERIFIED,
- VERIFICATION_LEVEL_ERROR,
VERIFICATION_LEVEL_EXISTS,
VERIFICATION_LEVEL_SIGNED_IN
} VerificationLevel;
@@ -46,6 +46,9 @@ struct _GoaKerberosIdentity
krb5_context kerberos_context;
krb5_ccache credentials_cache;
+ GHashTable *credentials_caches;
+ char *active_credentials_cache_name;
+
char *identifier;
guint identifier_idle_id;
@@ -109,6 +112,22 @@ G_DEFINE_TYPE_WITH_CODE (GoaKerberosIdentity,
initable_interface_init)
G_IMPLEMENT_INTERFACE (GOA_TYPE_IDENTITY,
identity_interface_init));
+
+static void
+close_credentials_caches (GoaKerberosIdentity *self)
+{
+ GHashTableIter iter;
+ const char *name;
+ krb5_ccache credentials_cache;
+
+ g_hash_table_iter_init (&iter, self->credentials_caches);
+ while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer*) &credentials_cache))
+ {
+ krb5_cc_close (self->kerberos_context, credentials_cache);
+ }
+ g_clear_pointer (&self->active_credentials_cache_name, g_free);
+}
+
static void
goa_kerberos_identity_dispose (GObject *object)
{
@@ -117,6 +136,8 @@ goa_kerberos_identity_dispose (GObject *object)
G_LOCK (identity_lock);
clear_alarms (self);
g_clear_pointer (&self->preauth_identity_source, g_free);
+ close_credentials_caches (self);
+ g_clear_pointer (&self->credentials_caches, g_hash_table_unref);
G_UNLOCK (identity_lock);
G_OBJECT_CLASS (goa_kerberos_identity_parent_class)->dispose (object);
@@ -130,9 +151,6 @@ goa_kerberos_identity_finalize (GObject *object)
g_free (self->identifier);
- if (self->credentials_cache != NULL)
- krb5_cc_close (self->kerberos_context, self->credentials_cache);
-
G_OBJECT_CLASS (goa_kerberos_identity_parent_class)->finalize (object);
}
@@ -255,11 +273,15 @@ get_identifier (GoaKerberosIdentity *self,
krb5_error_code error_code;
char *unparsed_name;
char *identifier = NULL;
+ krb5_ccache credentials_cache;
- if (self->credentials_cache == NULL)
+ if (self->active_credentials_cache_name == NULL)
return NULL;
- error_code = krb5_cc_get_principal (self->kerberos_context, self->credentials_cache, &principal);
+ credentials_cache = (krb5_ccache) g_hash_table_lookup (self->credentials_caches,
+ self->active_credentials_cache_name);
+
+ error_code = krb5_cc_get_principal (self->kerberos_context, credentials_cache, &principal);
if (error_code != 0)
{
if (error_code == KRB5_CC_END)
@@ -304,6 +326,7 @@ out:
static void
goa_kerberos_identity_init (GoaKerberosIdentity *self)
{
+ self->credentials_caches = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
}
static void
@@ -640,25 +663,31 @@ examine_credentials (GoaKerberosIdentity *self,
}
static VerificationLevel
-verify_identity (GoaKerberosIdentity *self,
- char **preauth_identity_source,
- GError **error)
+verify_identity_in_credentials_cache (GoaKerberosIdentity *self,
+ char **preauth_identity_source,
+ krb5_ccache credentials_cache,
+ krb5_timestamp *start_time,
+ krb5_timestamp *renewal_time,
+ krb5_timestamp *expiration_time,
+ 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 renewal_time = 0;
- krb5_timestamp expiration_time = 0;
VerificationLevel verification_level = VERIFICATION_LEVEL_UNVERIFIED;
- if (self->credentials_cache == NULL)
- goto out;
+ g_debug ("GoaKerberosIdentity: Verifying identity in credentials cache '%s'",
+ krb5_cc_get_name (self->kerberos_context, credentials_cache));
- error_code = krb5_cc_get_principal (self->kerberos_context, self->credentials_cache, &principal);
+ error_code = krb5_cc_get_principal (self->kerberos_context, credentials_cache, &principal);
if (error_code != 0)
{
+ if (error_code == KRB5_CC_END)
+ g_debug ("GoaKerberosIdentity: Credentials cache empty");
+ else if (error_code == KRB5_FCC_NOFILE)
+ g_debug ("GoaKerberosIdentity: Credentials cache missing");
+
if (error_code == KRB5_CC_END || error_code == KRB5_FCC_NOFILE)
goto out;
@@ -671,7 +700,7 @@ verify_identity (GoaKerberosIdentity *self,
goto out;
}
- error_code = krb5_cc_start_seq_get (self->kerberos_context, self->credentials_cache, &cursor);
+ error_code = krb5_cc_start_seq_get (self->kerberos_context, credentials_cache, &cursor);
if (error_code != 0)
{
set_and_prefix_error_from_krb5_error_code (self,
@@ -686,17 +715,18 @@ verify_identity (GoaKerberosIdentity *self,
verification_level = VERIFICATION_LEVEL_UNVERIFIED;
- error_code = krb5_cc_next_cred (self->kerberos_context, self->credentials_cache, &cursor, &credentials);
+ error_code = krb5_cc_next_cred (self->kerberos_context, credentials_cache, &cursor, &credentials);
while (error_code == 0)
{
if (credentials_validate_existence (self, principal, &credentials))
{
gboolean credentials_are_expired = TRUE;
- examine_credentials (self, &credentials,
- &start_time,
- &renewal_time,
- &expiration_time,
+ examine_credentials (self,
+ &credentials,
+ start_time,
+ renewal_time,
+ expiration_time,
&credentials_are_expired);
if (!credentials_are_expired)
@@ -710,7 +740,7 @@ verify_identity (GoaKerberosIdentity *self,
}
krb5_free_cred_contents (self->kerberos_context, &credentials);
- error_code = krb5_cc_next_cred (self->kerberos_context, self->credentials_cache, &cursor, &credentials);
+ error_code = krb5_cc_next_cred (self->kerberos_context, credentials_cache, &cursor, &credentials);
}
if (error_code != KRB5_CC_END)
@@ -722,11 +752,9 @@ verify_identity (GoaKerberosIdentity *self,
GOA_IDENTITY_ERROR_ENUMERATING_CREDENTIALS,
error_code,
_("Could not sift through identity credentials in cache: "));
- goto end_sequence;
}
- end_sequence:
- error_code = krb5_cc_end_seq_get (self->kerberos_context, self->credentials_cache, &cursor);
+ error_code = krb5_cc_end_seq_get (self->kerberos_context, credentials_cache, &cursor);
if (error_code != 0)
{
verification_level = VERIFICATION_LEVEL_ERROR;
@@ -739,16 +767,122 @@ verify_identity (GoaKerberosIdentity *self,
"identity credentials in cache: "));
goto out;
}
+
out:
+ switch (verification_level)
+ {
+ case VERIFICATION_LEVEL_EXISTS:
+ g_debug ("GoaKerberosIdentity: Credentials in credentials cache '%s' are out of date",
+ krb5_cc_get_name (self->kerberos_context, credentials_cache));
+ break;
+
+ case VERIFICATION_LEVEL_SIGNED_IN:
+ g_debug ("GoaKerberosIdentity: Credentials in credentials cache '%s' are valid",
+ krb5_cc_get_name (self->kerberos_context, credentials_cache));
+ break;
+
+ case VERIFICATION_LEVEL_UNVERIFIED:
+ g_debug ("GoaKerberosIdentity: Credentials in credentials cache '%s' are missing",
+ krb5_cc_get_name (self->kerberos_context, credentials_cache));
+ break;
+
+ case VERIFICATION_LEVEL_ERROR:
+ default:
+ g_debug ("GoaKerberosIdentity: Credentials in credentials cache '%s' could not be validated",
+ krb5_cc_get_name (self->kerberos_context, credentials_cache));
+ break;
+ }
+
+ if (principal != NULL)
+ krb5_free_principal (self->kerberos_context, principal);
+ return verification_level;
+}
+
+static VerificationLevel
+verify_identity (GoaKerberosIdentity *self,
+ char **preauth_identity_source,
+ GError **error)
+{
+ krb5_ccache credentials_cache;
+ const char *name;
+ krb5_timestamp start_time = 0;
+ krb5_timestamp renewal_time = 0;
+ krb5_timestamp expiration_time = 0;
+ VerificationLevel verification_level = VERIFICATION_LEVEL_UNVERIFIED;
+ GHashTableIter iter;
+
+ if (self->active_credentials_cache_name != NULL)
+ {
+ credentials_cache = (krb5_ccache) g_hash_table_lookup (self->credentials_caches,
+ self->active_credentials_cache_name);
+
+ verification_level = verify_identity_in_credentials_cache (self,
+ preauth_identity_source,
+ credentials_cache,
+ &start_time,
+ &renewal_time,
+ &expiration_time,
+ error);
+ if (verification_level == VERIFICATION_LEVEL_SIGNED_IN)
+ goto out;
+
+ if (verification_level == VERIFICATION_LEVEL_UNVERIFIED)
+ {
+ krb5_cc_close (self->kerberos_context, credentials_cache);
+ g_hash_table_remove (self->credentials_caches, self->active_credentials_cache_name);
+ g_clear_pointer (&self->active_credentials_cache_name, g_free);
+ }
+ }
+
+ self->start_time = 0;
+ self->renewal_time = 0;
+ self->expiration_time = 0;
+
+ g_hash_table_iter_init (&iter, self->credentials_caches);
+ while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer*) &credentials_cache))
+ {
+ krb5_timestamp new_start_time = 0;
+ krb5_timestamp new_renewal_time = 0;
+ krb5_timestamp new_expiration_time = 0;
+
+ if (g_strcmp0 (name, self->active_credentials_cache_name) == 0)
+ continue;
+
+ g_clear_pointer (preauth_identity_source, g_free);
+ verification_level = verify_identity_in_credentials_cache (self,
+ preauth_identity_source,
+ credentials_cache,
+ &new_start_time,
+ &new_renewal_time,
+ &new_expiration_time,
+ error);
+
+ if (verification_level == VERIFICATION_LEVEL_SIGNED_IN ||
+ self->active_credentials_cache_name == NULL)
+ {
+ g_clear_pointer (&self->active_credentials_cache_name, g_free);
+ self->active_credentials_cache_name = g_strdup (name);
+ start_time = new_start_time;
+ renewal_time = new_renewal_time;
+ expiration_time = new_expiration_time;
+
+ if (verification_level == VERIFICATION_LEVEL_SIGNED_IN)
+ break;
+ }
+ else if (verification_level == VERIFICATION_LEVEL_UNVERIFIED)
+ {
+ krb5_cc_close (self->kerberos_context, credentials_cache);
+ g_hash_table_iter_remove (&iter);
+ }
+ }
+out:
G_LOCK (identity_lock);
set_start_time (self, start_time);
set_renewal_time (self, renewal_time);
set_expiration_time (self, expiration_time);
G_UNLOCK (identity_lock);
- if (principal != NULL)
- krb5_free_principal (self->kerberos_context, principal);
return verification_level;
}
@@ -1079,11 +1213,37 @@ on_kerberos_inquiry (krb5_context kerberos_context,
return error_code;
}
+static void
+goa_kerberos_identity_add_credentials_cache (GoaKerberosIdentity *self,
+ krb5_ccache credentials_cache)
+{
+ const char *cache_name;
+
+ cache_name = krb5_cc_get_name (self->kerberos_context, credentials_cache);
+
+ if (g_hash_table_contains (self->credentials_caches, cache_name))
+ {
+ krb5_ccache old_credentials_cache;
+
+ old_credentials_cache = (krb5_ccache) g_hash_table_lookup (self->credentials_caches, cache_name);
+
+ krb5_cc_close (self->kerberos_context, old_credentials_cache);
+ }
+
+ g_hash_table_replace (self->credentials_caches, g_strdup (cache_name), credentials_cache);
+
+ if (self->active_credentials_cache_name == NULL)
+ {
+ self->active_credentials_cache_name = g_strdup (cache_name);
+ }
+}
+
static gboolean
-create_credential_cache (GoaKerberosIdentity *self,
- GError **error)
+create_credentials_cache (GoaKerberosIdentity *self,
+ GError **error)
{
krb5_ccache default_cache;
+ krb5_ccache new_cache;
const char *cache_type;
krb5_error_code error_code;
@@ -1092,7 +1252,7 @@ create_credential_cache (GoaKerberosIdentity *self,
if (error_code == 0)
{
cache_type = krb5_cc_get_type (self->kerberos_context, default_cache);
- error_code = krb5_cc_new_unique (self->kerberos_context, cache_type, NULL, &self->credentials_cache);
+ error_code = krb5_cc_new_unique (self->kerberos_context, cache_type, NULL, &new_cache);
}
if (error_code != 0)
@@ -1106,6 +1266,8 @@ create_credential_cache (GoaKerberosIdentity *self,
return FALSE;
}
+ goa_kerberos_identity_add_credentials_cache (self, new_cache);
+
return TRUE;
}
@@ -1116,17 +1278,22 @@ goa_kerberos_identity_update_credentials (GoaKerberosIdentity *self,
GError **error)
{
krb5_error_code error_code;
+ krb5_ccache credentials_cache;
- if (self->credentials_cache == NULL)
+
+ if (self->active_credentials_cache_name == NULL)
{
- if (!create_credential_cache (self, error))
+ if (!create_credentials_cache (self, error))
{
krb5_free_cred_contents (self->kerberos_context, new_credentials);
goto out;
}
}
- error_code = krb5_cc_initialize (self->kerberos_context, self->credentials_cache, principal);
+ credentials_cache = (krb5_ccache) g_hash_table_lookup (self->credentials_caches,
+ self->active_credentials_cache_name);
+
+ error_code = krb5_cc_initialize (self->kerberos_context, credentials_cache, principal);
if (error_code != 0)
{
set_and_prefix_error_from_krb5_error_code (self,
@@ -1139,7 +1306,7 @@ goa_kerberos_identity_update_credentials (GoaKerberosIdentity *self,
goto out;
}
- error_code = krb5_cc_store_cred (self->kerberos_context, self->credentials_cache, new_credentials);
+ error_code = krb5_cc_store_cred (self->kerberos_context, credentials_cache, new_credentials);
if (error_code != 0)
{
set_and_prefix_error_from_krb5_error_code (self,
@@ -1354,6 +1521,40 @@ update_identifier (GoaKerberosIdentity *self, GoaKerberosIdentity *new_identity)
}
}
+static int
+goa_kerberos_identity_compare (GoaKerberosIdentity *self,
+ GoaKerberosIdentity *new_identity)
+{
+ if (self->cached_verification_level < new_identity->cached_verification_level)
+ return -100;
+
+ if (self->cached_verification_level > new_identity->cached_verification_level)
+ return 100;
+
+ if (self->cached_verification_level != VERIFICATION_LEVEL_SIGNED_IN)
+ return 50;
+
+ if (self->expiration_time < new_identity->expiration_time)
+ return -10;
+
+ if (self->expiration_time > new_identity->expiration_time)
+ return 10;
+
+ if (self->start_time > new_identity->start_time)
+ return -5;
+
+ if (self->start_time < new_identity->start_time)
+ return 5;
+
+ if (self->renewal_time < new_identity->renewal_time)
+ return -1;
+
+ if (self->renewal_time > new_identity->renewal_time)
+ return 1;
+
+ return 0;
+}
+
void
goa_kerberos_identity_update (GoaKerberosIdentity *self,
GoaKerberosIdentity *new_identity)
@@ -1361,15 +1562,30 @@ goa_kerberos_identity_update (GoaKerberosIdentity *self,
VerificationLevel old_verification_level, new_verification_level;
gboolean time_changed = FALSE;
char *preauth_identity_source = NULL;
+ int comparison;
+
+ comparison = goa_kerberos_identity_compare (self, new_identity);
+
+ if (new_identity->active_credentials_cache_name != NULL)
+ {
+ krb5_ccache credentials_cache;
+ krb5_ccache copied_cache;
- if (self->credentials_cache != NULL)
- krb5_cc_close (self->kerberos_context, self->credentials_cache);
+ credentials_cache = (krb5_ccache) g_hash_table_lookup (new_identity->credentials_caches,
+ new_identity->active_credentials_cache_name);
+ krb5_cc_dup (new_identity->kerberos_context, credentials_cache, &copied_cache);
- krb5_cc_dup (new_identity->kerberos_context, new_identity->credentials_cache, &self->credentials_cache);
+ if (comparison < 0)
+ g_clear_pointer (&self->active_credentials_cache_name, &g_free);
+
+ goa_kerberos_identity_add_credentials_cache (self, copied_cache);
+ }
+
+ if (comparison >= 0)
+ return;
G_LOCK (identity_lock);
update_identifier (self, new_identity);
-
time_changed |= set_start_time (self, new_identity->start_time);
time_changed |= set_renewal_time (self, new_identity->renewal_time);
time_changed |= set_expiration_time (self, new_identity->expiration_time);
@@ -1426,10 +1642,11 @@ goa_kerberos_identity_renew (GoaKerberosIdentity *self, GError **error)
krb5_error_code error_code = 0;
krb5_principal principal;
krb5_creds new_credentials;
+ krb5_ccache credentials_cache;
gboolean renewed = FALSE;
char *name = NULL;
- if (self->credentials_cache == NULL)
+ if (self->active_credentials_cache_name == NULL)
{
g_set_error (error,
GOA_IDENTITY_ERROR,
@@ -1438,7 +1655,9 @@ goa_kerberos_identity_renew (GoaKerberosIdentity *self, GError **error)
goto out;
}
- error_code = krb5_cc_get_principal (self->kerberos_context, self->credentials_cache, &principal);
+ credentials_cache = (krb5_ccache) g_hash_table_lookup (self->credentials_caches,
+ self->active_credentials_cache_name);
+ error_code = krb5_cc_get_principal (self->kerberos_context, credentials_cache, &principal);
if (error_code != 0)
{
set_and_prefix_error_from_krb5_error_code (self,
@@ -1451,7 +1670,7 @@ goa_kerberos_identity_renew (GoaKerberosIdentity *self, GError **error)
name = goa_kerberos_identity_get_principal_name (self);
- error_code = krb5_get_renewed_creds (self->kerberos_context, &new_credentials, principal, self->credentials_cache, NULL);
+ error_code = krb5_get_renewed_creds (self->kerberos_context, &new_credentials, principal, credentials_cache, NULL);
if (error_code != 0)
{
set_and_prefix_error_from_krb5_error_code (self,
@@ -1486,36 +1705,51 @@ out:
gboolean
goa_kerberos_identity_erase (GoaKerberosIdentity *self, GError **error)
{
+ GHashTableIter iter;
+ const char *name;
+ krb5_ccache credentials_cache;
krb5_error_code error_code = 0;
- if (self->credentials_cache != NULL)
+ if (self->active_credentials_cache_name != NULL)
{
- error_code = krb5_cc_destroy (self->kerberos_context, self->credentials_cache);
- self->credentials_cache = NULL;
+ credentials_cache = (krb5_ccache) g_hash_table_lookup (self->credentials_caches,
+ self->active_credentials_cache_name);
+ g_debug ("GoaKerberosIdentity: Destroying active credentials cache %s", self->active_credentials_cache_name);
+ error_code = krb5_cc_destroy (self->kerberos_context, credentials_cache);
+ g_clear_pointer (&self->active_credentials_cache_name, g_free);
+
+ if (error_code != 0)
+ {
+ set_and_prefix_error_from_krb5_error_code (self,
+ error,
+ GOA_IDENTITY_ERROR_REMOVING_CREDENTIALS,
+ error_code, _("Could not erase identity: "));
+ }
}
- if (error_code != 0)
+ g_hash_table_iter_init (&iter, self->credentials_caches);
+ while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer*) &credentials_cache))
{
- set_and_prefix_error_from_krb5_error_code (self,
- error,
- GOA_IDENTITY_ERROR_REMOVING_CREDENTIALS,
- error_code, _("Could not erase identity: "));
- return FALSE;
+ g_debug ("GoaKerberosIdentity: Destroying inactive credentials cache %s", name);
+ krb5_cc_destroy (self->kerberos_context, credentials_cache);
}
+ g_hash_table_remove_all (self->credentials_caches);
- return TRUE;
+ return error_code == 0;
}
GoaIdentity *
goa_kerberos_identity_new (krb5_context context, krb5_ccache cache, GError **error)
{
GoaKerberosIdentity *self;
+ krb5_ccache copied_cache;
self = GOA_KERBEROS_IDENTITY (g_object_new (GOA_TYPE_KERBEROS_IDENTITY, NULL));
-
- krb5_cc_dup (context, cache, &self->credentials_cache);
self->kerberos_context = context;
+ krb5_cc_dup (self->kerberos_context, cache, &copied_cache);
+ goa_kerberos_identity_add_credentials_cache (self, copied_cache);
+
error = NULL;
if (!g_initable_init (G_INITABLE (self), NULL, error))
{
--
GitLab
From 3e80e12c441348b69ce51b5799a9579ab1f81d53 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Mon, 28 Nov 2022 15:58:09 -0500
Subject: [PATCH 2/2] kerberos-identity: Clear alarms on temporary identity
When the identity service does a refresh, it creates a new temporary
identity object to check the credentials, then it merges that
temporary identity into the preexisting identity object (so the
pointers don't change).
This has the unfortunate side-effect of arming expiration alarms in
the temporary object, that can then fire immediately before the object
is thrown out.
This commit disarms those alarms so they don't fire needlessly.
---
src/goaidentity/goakerberosidentity.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/goaidentity/goakerberosidentity.c b/src/goaidentity/goakerberosidentity.c
index dbb5991d..6006385b 100644
--- a/src/goaidentity/goakerberosidentity.c
+++ b/src/goaidentity/goakerberosidentity.c
@@ -1581,6 +1581,8 @@ goa_kerberos_identity_update (GoaKerberosIdentity *self,
goa_kerberos_identity_add_credentials_cache (self, copied_cache);
}
+ clear_alarms (new_identity);
+
if (comparison >= 0)
return;
--
GitLab

View File

@ -1,35 +0,0 @@
From 8c5b63069dfbf36ac662369d9ba3fb4ab0d2efb2 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 15 Dec 2022 14:46:01 -0500
Subject: [PATCH 2/2] kerberos-identity: Fix buglet in update_identity
The update_identity function is supposed to transfer the identity
form one object to another.
In practice, this is currently always a noop because only objects
with the same identities get copied to each other.
Nevertheless, there is a bug in the function. It grabs the identity
from the target object instead of from the source object.
This commit fixes that.
---
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 a20c0438..bc607966 100644
--- a/src/goaidentity/goakerberosidentity.c
+++ b/src/goaidentity/goakerberosidentity.c
@@ -1507,7 +1507,7 @@ update_identifier (GoaKerberosIdentity *self, GoaKerberosIdentity *new_identity)
{
char *new_identifier;
- new_identifier = get_identifier (self, NULL);
+ new_identifier = get_identifier (new_identity, NULL);
if (g_strcmp0 (self->identifier, new_identifier) != 0 && new_identifier != NULL)
{
g_free (self->identifier);
--
GitLab

278
116.patch
View File

@ -1,278 +0,0 @@
From c17527f4996614bd7fcefde6e1f8949c61d3c96c Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 15 Dec 2022 16:27:27 -0500
Subject: [PATCH 1/2] goakerberosidentity: Fix crash when erasing credentials
Right now when erasing an identity we erase the
active credentials first and then the inactive
ones.
We neglect to take the active one out of the hash
table, though, so it gets destroyed twice.
This commit fixes that.
---
src/goaidentity/goakerberosidentity.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/goaidentity/goakerberosidentity.c b/src/goaidentity/goakerberosidentity.c
index 9e9b8a74..ac550f12 100644
--- a/src/goaidentity/goakerberosidentity.c
+++ b/src/goaidentity/goakerberosidentity.c
@@ -1686,60 +1686,62 @@ goa_kerberos_identity_renew (GoaKerberosIdentity *self, GError **error)
{
goto free_principal;
}
g_debug ("GoaKerberosIdentity: identity %s renewed", name);
renewed = TRUE;
free_principal:
krb5_free_principal (self->kerberos_context, principal);
out:
g_free (name);
return renewed;
}
gboolean
goa_kerberos_identity_erase (GoaKerberosIdentity *self, GError **error)
{
GHashTableIter iter;
const char *name;
krb5_ccache credentials_cache;
krb5_error_code error_code = 0;
if (self->active_credentials_cache_name != NULL)
{
credentials_cache = (krb5_ccache) g_hash_table_lookup (self->credentials_caches,
self->active_credentials_cache_name);
g_debug ("GoaKerberosIdentity: Destroying active credentials cache %s", self->active_credentials_cache_name);
error_code = krb5_cc_destroy (self->kerberos_context, credentials_cache);
+ g_hash_table_remove (self->credentials_caches, self->active_credentials_cache_name);
+
g_clear_pointer (&self->active_credentials_cache_name, g_free);
if (error_code != 0)
{
set_and_prefix_error_from_krb5_error_code (self,
error,
GOA_IDENTITY_ERROR_REMOVING_CREDENTIALS,
error_code, _("Could not erase identity: "));
}
}
g_hash_table_iter_init (&iter, self->credentials_caches);
while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer*) &credentials_cache))
{
g_debug ("GoaKerberosIdentity: Destroying inactive credentials cache %s", name);
krb5_cc_destroy (self->kerberos_context, credentials_cache);
}
g_hash_table_remove_all (self->credentials_caches);
return error_code == 0;
}
GoaIdentity *
goa_kerberos_identity_new (krb5_context context, krb5_ccache cache, GError **error)
{
GoaKerberosIdentity *self;
krb5_ccache copied_cache;
self = GOA_KERBEROS_IDENTITY (g_object_new (GOA_TYPE_KERBEROS_IDENTITY, NULL));
self->kerberos_context = context;
--
2.37.0.rc1
From 2bb898f5137d09e998e2d5ad0127a65df8cf15e0 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 15 Dec 2022 15:35:49 -0500
Subject: [PATCH 2/2] goakerberosidentity: Explicitly switch to credentials
cache when needed
If we're updating a credentials cache and decide
it should be the new default for an identity, and
the old credentials cache was the default cache
for the cache collection then we should make the
new credential cache the default cache for the
collection, too.
This commit adds that. It also makes the new
credentials cache the default if there wasn't a
valid default set already. This brings consistency
to differences in behavior from different kerberos
ccache types.
---
src/goaidentity/goakerberosidentity.c | 65 +++++++++++++++++++++++++--
1 file changed, 62 insertions(+), 3 deletions(-)
diff --git a/src/goaidentity/goakerberosidentity.c b/src/goaidentity/goakerberosidentity.c
index ac550f12..71c1ff09 100644
--- a/src/goaidentity/goakerberosidentity.c
+++ b/src/goaidentity/goakerberosidentity.c
@@ -1524,98 +1524,157 @@ goa_kerberos_identity_compare (GoaKerberosIdentity *self,
if (self->cached_verification_level < new_identity->cached_verification_level)
return -100;
if (self->cached_verification_level > new_identity->cached_verification_level)
return 100;
if (self->cached_verification_level != VERIFICATION_LEVEL_SIGNED_IN)
return 50;
if (self->expiration_time < new_identity->expiration_time)
return -10;
if (self->expiration_time > new_identity->expiration_time)
return 10;
if (self->start_time > new_identity->start_time)
return -5;
if (self->start_time < new_identity->start_time)
return 5;
if (self->renewal_time < new_identity->renewal_time)
return -1;
if (self->renewal_time > new_identity->renewal_time)
return 1;
return 0;
}
+static char *
+get_default_cache_name (GoaKerberosIdentity *self)
+{
+ int error_code;
+ krb5_ccache default_cache;
+ krb5_principal principal;
+ char *default_cache_name;
+ char *principal_name;
+
+ error_code = krb5_cc_default (self->kerberos_context, &default_cache);
+
+ if (error_code != 0)
+ return NULL;
+
+ /* Return NULL if the default cache doesn't pass basic sanity checks
+ */
+ error_code = krb5_cc_get_principal (self->kerberos_context, default_cache, &principal);
+
+ if (error_code != 0)
+ return NULL;
+
+ error_code = krb5_unparse_name_flags (self->kerberos_context, principal, 0, &principal_name);
+ krb5_free_principal (self->kerberos_context, principal);
+
+ if (error_code != 0)
+ return NULL;
+
+ krb5_free_unparsed_name (self->kerberos_context, principal_name);
+
+ default_cache_name = g_strdup (krb5_cc_get_name (self->kerberos_context, default_cache));
+ krb5_cc_close (self->kerberos_context, default_cache);
+
+ return default_cache_name;
+}
+
void
goa_kerberos_identity_update (GoaKerberosIdentity *self,
GoaKerberosIdentity *new_identity)
{
VerificationLevel old_verification_level, new_verification_level;
gboolean time_changed = FALSE;
char *preauth_identity_source = NULL;
int comparison;
+ G_LOCK (identity_lock);
+
+ old_verification_level = self->cached_verification_level;
+ new_verification_level = new_identity->cached_verification_level;
+
comparison = goa_kerberos_identity_compare (self, new_identity);
if (new_identity->active_credentials_cache_name != NULL)
{
+ g_autofree char *default_cache_name = NULL;
krb5_ccache credentials_cache;
krb5_ccache copied_cache;
+ gboolean should_switch_to_new_credentials_cache = FALSE;
+
+ default_cache_name = get_default_cache_name (self);
+
+ if (default_cache_name == NULL)
+ should_switch_to_new_credentials_cache = TRUE;
credentials_cache = (krb5_ccache) g_hash_table_lookup (new_identity->credentials_caches,
new_identity->active_credentials_cache_name);
krb5_cc_dup (new_identity->kerberos_context, credentials_cache, &copied_cache);
+ if (g_strcmp0 (default_cache_name, self->active_credentials_cache_name) == 0)
+ {
+ if ((comparison < 0) ||
+ (comparison == 0 && old_verification_level != VERIFICATION_LEVEL_SIGNED_IN))
+ should_switch_to_new_credentials_cache = TRUE;
+ }
+
if (comparison < 0)
- g_clear_pointer (&self->active_credentials_cache_name, &g_free);
+ {
+ g_clear_pointer (&self->active_credentials_cache_name, g_free);
+ self->active_credentials_cache_name = g_strdup (new_identity->active_credentials_cache_name);
+ }
goa_kerberos_identity_add_credentials_cache (self, copied_cache);
+
+ if (should_switch_to_new_credentials_cache)
+ krb5_cc_switch (self->kerberos_context, copied_cache);
}
+ G_UNLOCK (identity_lock);
clear_alarms (new_identity);
if (comparison >= 0)
return;
G_LOCK (identity_lock);
update_identifier (self, new_identity);
time_changed |= set_start_time (self, new_identity->start_time);
time_changed |= set_renewal_time (self, new_identity->renewal_time);
time_changed |= set_expiration_time (self, new_identity->expiration_time);
- old_verification_level = self->cached_verification_level;
- new_verification_level = new_identity->cached_verification_level;
G_UNLOCK (identity_lock);
if (time_changed)
{
if (new_verification_level == VERIFICATION_LEVEL_SIGNED_IN)
reset_alarms (self);
else
clear_alarms (self);
}
G_LOCK (identity_lock);
g_free (self->preauth_identity_source);
self->preauth_identity_source = preauth_identity_source;
G_UNLOCK (identity_lock);
if (new_verification_level != old_verification_level)
{
if (old_verification_level == VERIFICATION_LEVEL_SIGNED_IN &&
new_verification_level == VERIFICATION_LEVEL_EXISTS)
{
G_LOCK (identity_lock);
self->cached_verification_level = new_verification_level;
G_UNLOCK (identity_lock);
g_signal_emit (G_OBJECT (self), signals[EXPIRED], 0);
}
else if (old_verification_level == VERIFICATION_LEVEL_EXISTS &&
new_verification_level == VERIFICATION_LEVEL_SIGNED_IN)
{
G_LOCK (identity_lock);
--
2.37.0.rc1

View File

@ -6,7 +6,7 @@
Name: gnome-online-accounts Name: gnome-online-accounts
Version: 3.46.0 Version: 3.46.0
Release: 5%{?dist} Release: 6%{?dist}
Summary: Single sign-on framework for GNOME Summary: Single sign-on framework for GNOME
License: LGPLv2+ License: LGPLv2+
@ -17,9 +17,7 @@ Source0: https://download.gnome.org/sources/gnome-online-accounts/3.46/%{name}-%
# https://gitlab.gnome.org/GNOME/gnome-online-accounts/-/issues/63 # https://gitlab.gnome.org/GNOME/gnome-online-accounts/-/issues/63
# https://bugzilla.redhat.com/show_bug.cgi?id=1913641 # https://bugzilla.redhat.com/show_bug.cgi?id=1913641
Patch0: 0001-google-Remove-Photos-support.patch Patch0: 0001-google-Remove-Photos-support.patch
Patch1: 112.patch Patch1: kerberos-fixes.patch
Patch2: 115.patch
Patch3: 116.patch
BuildRequires: pkgconfig(gcr-3) BuildRequires: pkgconfig(gcr-3)
@ -67,8 +65,6 @@ developing applications that use %{name}.
%endif %endif
%patch1 -p1 %patch1 -p1
%patch2 -p1
%patch3 -p1
%build %build
%meson \ %meson \
@ -127,6 +123,10 @@ developing applications that use %{name}.
%{_datadir}/vala/ %{_datadir}/vala/
%changelog %changelog
* Fri Jan 20 2023 Ray Strode <rstrode@redhat.com> - 3.46.0-6
- Add more kerberos fixes from upstream
Related: #2152695
* Thu Jan 19 2023 Fedora Release Engineering <releng@fedoraproject.org> - 3.46.0-5 * Thu Jan 19 2023 Fedora Release Engineering <releng@fedoraproject.org> - 3.46.0-5
- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild - Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild

4461
kerberos-fixes.patch Normal file

File diff suppressed because it is too large Load Diff