Blame SOURCES/kerberos-fix-renewal.patch

1e691d
From 3d9361b917ef923f39ba54835512171d83e457b7 Mon Sep 17 00:00:00 2001
1e691d
From: Ray Strode <rstrode@redhat.com>
1e691d
Date: Tue, 22 Sep 2015 14:33:35 -0400
1e691d
Subject: [PATCH 1/3] identity: consider ticket start time when calculating
1e691d
 renewal time
1e691d
1e691d
Right now we try to renew the kerberos ticket at the midpoint between
1e691d
when we first set up the renewal alarm and when the ticket expires.
1e691d
1e691d
Unfortunately, this doesn't work for kernel keyring based kerberos
1e691d
tickets, since the alarms are reset on a regular interval (as part
1e691d
of the polling process to check for updates, since kernel keyring
1e691d
doesn't have changed notification). Since the alarms are reset
1e691d
regularly, the midpoint converges toward the end of the ticket
1e691d
lifetime.
1e691d
1e691d
Instead, we should consider the ticket start time, which remains
1e691d
constant.  This commit tracks the ticket start time, and changes
1e691d
the code renewal alarm to use the mid point between the start time
1e691d
and expiration time of the ticket.
1e691d
---
1e691d
 src/goaidentity/goaidentity.c         |  7 +++++
1e691d
 src/goaidentity/goakerberosidentity.c | 55 +++++++++++++++++++++++++++++------
1e691d
 2 files changed, 53 insertions(+), 9 deletions(-)
1e691d
1e691d
diff --git a/src/goaidentity/goaidentity.c b/src/goaidentity/goaidentity.c
1e691d
index 2fc491b..2904e2a 100644
1e691d
--- a/src/goaidentity/goaidentity.c
1e691d
+++ b/src/goaidentity/goaidentity.c
1e691d
@@ -13,60 +13,67 @@
1e691d
  * Lesser General Public License for more details.
1e691d
  *
1e691d
  * You should have received a copy of the GNU Lesser General
1e691d
  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
1e691d
  */
1e691d
 
1e691d
 #include "config.h"
1e691d
 
1e691d
 #include <glib-object.h>
1e691d
 #include <glib/gi18n.h>
1e691d
 
1e691d
 #include "goaidentity.h"
1e691d
 
1e691d
 G_DEFINE_INTERFACE (GoaIdentity, goa_identity, G_TYPE_OBJECT);
1e691d
 
1e691d
 static void
1e691d
 goa_identity_default_init (GoaIdentityInterface *interface)
1e691d
 {
1e691d
   g_object_interface_install_property (interface,
1e691d
                                        g_param_spec_string ("identifier",
1e691d
                                                             "identifier",
1e691d
                                                             "identifier",
1e691d
                                                             NULL, G_PARAM_READABLE));
1e691d
   g_object_interface_install_property (interface,
1e691d
                                        g_param_spec_boolean ("is-signed-in",
1e691d
                                                              "Is signed in",
1e691d
                                                              "Whether or not identity is currently signed in",
1e691d
                                                              FALSE,
1e691d
                                                              G_PARAM_READABLE));
1e691d
   g_object_interface_install_property (interface,
1e691d
+                                       g_param_spec_int64 ("start-timestamp",
1e691d
+                                                           "Start Timestamp",
1e691d
+                                                           "A timestamp of when the identities credentials first became valid",
1e691d
+                                                           -1,
1e691d
+                                                           G_MAXINT64,
1e691d
+                                                           -1, G_PARAM_READABLE));
1e691d
+  g_object_interface_install_property (interface,
1e691d
                                        g_param_spec_int64 ("expiration-timestamp",
1e691d
                                                            "Expiration Timestamp",
1e691d
                                                            "A timestamp of when the identities credentials expire",
1e691d
                                                            -1,
1e691d
                                                            G_MAXINT64,
1e691d
                                                            -1, G_PARAM_READABLE));
1e691d
 }
1e691d
 
1e691d
 GQuark
1e691d
 goa_identity_error_quark (void)
1e691d
 {
1e691d
   static GQuark error_quark = 0;
1e691d
 
1e691d
   if (error_quark == 0)
1e691d
     {
1e691d
       error_quark = g_quark_from_static_string ("goa-identity-error");
1e691d
     }
1e691d
 
1e691d
   return error_quark;
1e691d
 }
1e691d
 
1e691d
 const char *
1e691d
 goa_identity_get_identifier (GoaIdentity *self)
1e691d
 {
1e691d
   return GOA_IDENTITY_GET_IFACE (self)->get_identifier (self);
1e691d
 }
1e691d
 
1e691d
 gboolean
1e691d
 goa_identity_is_signed_in (GoaIdentity *self)
1e691d
 {
1e691d
diff --git a/src/goaidentity/goakerberosidentity.c b/src/goaidentity/goakerberosidentity.c
1e691d
index 4370a09..6865535 100644
1e691d
--- a/src/goaidentity/goakerberosidentity.c
1e691d
+++ b/src/goaidentity/goakerberosidentity.c
1e691d
@@ -22,86 +22,89 @@
1e691d
 #include "goakerberosidentity.h"
1e691d
 #include "goakerberosidentityinquiry.h"
1e691d
 #include "goaalarm.h"
1e691d
 
1e691d
 #include <netinet/in.h>
1e691d
 #include <arpa/nameser.h>
1e691d
 #include <resolv.h>
1e691d
 
1e691d
 #include <string.h>
1e691d
 #include <glib/gi18n.h>
1e691d
 #include <gio/gio.h>
1e691d
 
1e691d
 typedef enum
1e691d
 {
1e691d
   VERIFICATION_LEVEL_UNVERIFIED,
1e691d
   VERIFICATION_LEVEL_ERROR,
1e691d
   VERIFICATION_LEVEL_EXISTS,
1e691d
   VERIFICATION_LEVEL_SIGNED_IN
1e691d
 } VerificationLevel;
1e691d
 
1e691d
 struct _GoaKerberosIdentityPrivate
1e691d
 {
1e691d
   krb5_context kerberos_context;
1e691d
   krb5_ccache  credentials_cache;
1e691d
 
1e691d
   char *identifier;
1e691d
   guint identifier_idle_id;
1e691d
 
1e691d
   char *preauth_identity_source;
1e691d
 
1e691d
+  krb5_timestamp start_time;
1e691d
+  guint          start_time_idle_id;
1e691d
   krb5_timestamp expiration_time;
1e691d
   guint          expiration_time_idle_id;
1e691d
 
1e691d
   GoaAlarm     *expiration_alarm;
1e691d
   GoaAlarm     *expiring_alarm;
1e691d
   GoaAlarm     *renewal_alarm;
1e691d
 
1e691d
   VerificationLevel cached_verification_level;
1e691d
   guint             is_signed_in_idle_id;
1e691d
 };
1e691d
 
1e691d
 enum
1e691d
 {
1e691d
   EXPIRING,
1e691d
   EXPIRED,
1e691d
   UNEXPIRED,
1e691d
   NEEDS_RENEWAL,
1e691d
   NEEDS_REFRESH,
1e691d
   NUMBER_OF_SIGNALS,
1e691d
 };
1e691d
 
1e691d
 enum
1e691d
 {
1e691d
   PROP_0,
1e691d
   PROP_IDENTIFIER,
1e691d
   PROP_IS_SIGNED_IN,
1e691d
+  PROP_START_TIMESTAMP,
1e691d
   PROP_EXPIRATION_TIMESTAMP
1e691d
 };
1e691d
 
1e691d
 static guint signals[NUMBER_OF_SIGNALS] = { 0 };
1e691d
 
1e691d
 static void identity_interface_init (GoaIdentityInterface *interface);
1e691d
 static void initable_interface_init (GInitableIface *interface);
1e691d
 static void reset_alarms (GoaKerberosIdentity *self);
1e691d
 static void clear_alarms (GoaKerberosIdentity *self);
1e691d
 static gboolean goa_kerberos_identity_is_signed_in (GoaIdentity *identity);
1e691d
 static void set_error_from_krb5_error_code (GoaKerberosIdentity  *self,
1e691d
                                             GError              **error,
1e691d
                                             gint                  code,
1e691d
                                             krb5_error_code       error_code,
1e691d
                                             const char           *format,
1e691d
                                             ...);
1e691d
 
1e691d
 G_LOCK_DEFINE_STATIC (identity_lock);
1e691d
 
1e691d
 G_DEFINE_TYPE_WITH_CODE (GoaKerberosIdentity,
1e691d
                          goa_kerberos_identity,
1e691d
                          G_TYPE_OBJECT,
1e691d
                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
1e691d
                                                 initable_interface_init)
1e691d
                          G_IMPLEMENT_INTERFACE (GOA_TYPE_IDENTITY,
1e691d
                                                 identity_interface_init));
1e691d
 static void
1e691d
 goa_kerberos_identity_dispose (GObject *object)
1e691d
 {
1e691d
   GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (object);
1e691d
@@ -121,60 +124,65 @@ goa_kerberos_identity_finalize (GObject *object)
1e691d
 {
1e691d
   GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (object);
1e691d
 
1e691d
   g_free (self->priv->identifier);
1e691d
 
1e691d
   if (self->priv->credentials_cache != NULL)
1e691d
     krb5_cc_close (self->priv->kerberos_context, self->priv->credentials_cache);
1e691d
 
1e691d
   G_OBJECT_CLASS (goa_kerberos_identity_parent_class)->finalize (object);
1e691d
 }
1e691d
 
1e691d
 static void
1e691d
 goa_kerberos_identity_get_property (GObject    *object,
1e691d
                                     guint       property_id,
1e691d
                                     GValue     *value,
1e691d
                                     GParamSpec *param_spec)
1e691d
 {
1e691d
   GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (object);
1e691d
 
1e691d
   switch (property_id)
1e691d
     {
1e691d
     case PROP_IDENTIFIER:
1e691d
       G_LOCK (identity_lock);
1e691d
       g_value_set_string (value, self->priv->identifier);
1e691d
       G_UNLOCK (identity_lock);
1e691d
       break;
1e691d
     case PROP_IS_SIGNED_IN:
1e691d
       g_value_set_boolean (value,
1e691d
                            goa_kerberos_identity_is_signed_in (GOA_IDENTITY (self)));
1e691d
       break;
1e691d
+    case PROP_START_TIMESTAMP:
1e691d
+      G_LOCK (identity_lock);
1e691d
+      g_value_set_int64 (value, (gint64) self->priv->start_time);
1e691d
+      G_UNLOCK (identity_lock);
1e691d
+      break;
1e691d
     case PROP_EXPIRATION_TIMESTAMP:
1e691d
       G_LOCK (identity_lock);
1e691d
       g_value_set_int64 (value, (gint64) self->priv->expiration_time);
1e691d
       G_UNLOCK (identity_lock);
1e691d
       break;
1e691d
     default:
1e691d
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
1e691d
       break;
1e691d
     }
1e691d
 }
1e691d
 
1e691d
 static void
1e691d
 goa_kerberos_identity_class_init (GoaKerberosIdentityClass *klass)
1e691d
 {
1e691d
   GObjectClass *object_class;
1e691d
 
1e691d
   object_class = G_OBJECT_CLASS (klass);
1e691d
 
1e691d
   object_class->dispose = goa_kerberos_identity_dispose;
1e691d
   object_class->finalize = goa_kerberos_identity_finalize;
1e691d
   object_class->get_property = goa_kerberos_identity_get_property;
1e691d
 
1e691d
   g_type_class_add_private (klass, sizeof (GoaKerberosIdentityPrivate));
1e691d
 
1e691d
   signals[EXPIRING] = g_signal_new ("expiring",
1e691d
                                     G_TYPE_FROM_CLASS (klass),
1e691d
                                     G_SIGNAL_RUN_LAST,
1e691d
                                     0,
1e691d
                                     NULL,
1e691d
                                     NULL,
1e691d
@@ -194,60 +202,63 @@ goa_kerberos_identity_class_init (GoaKerberosIdentityClass *klass)
1e691d
                                      G_TYPE_FROM_CLASS (klass),
1e691d
                                      G_SIGNAL_RUN_LAST,
1e691d
                                      0,
1e691d
                                      NULL,
1e691d
                                      NULL,
1e691d
                                      NULL,
1e691d
                                      G_TYPE_NONE,
1e691d
                                      0);
1e691d
   signals[NEEDS_RENEWAL] = g_signal_new ("needs-renewal",
1e691d
                                          G_TYPE_FROM_CLASS (klass),
1e691d
                                          G_SIGNAL_RUN_LAST,
1e691d
                                          0,
1e691d
                                          NULL,
1e691d
                                          NULL,
1e691d
                                          NULL,
1e691d
                                          G_TYPE_NONE,
1e691d
                                          0);
1e691d
   signals[NEEDS_REFRESH] = g_signal_new ("needs-refresh",
1e691d
                                          G_TYPE_FROM_CLASS (klass),
1e691d
                                          G_SIGNAL_RUN_LAST,
1e691d
                                          0,
1e691d
                                          NULL,
1e691d
                                          NULL,
1e691d
                                          NULL,
1e691d
                                          G_TYPE_NONE,
1e691d
                                          0);
1e691d
 
1e691d
   g_object_class_override_property (object_class, PROP_IDENTIFIER, "identifier");
1e691d
   g_object_class_override_property (object_class, PROP_IS_SIGNED_IN, "is-signed-in");
1e691d
   g_object_class_override_property (object_class,
1e691d
+                                    PROP_START_TIMESTAMP,
1e691d
+                                    "start-timestamp");
1e691d
+  g_object_class_override_property (object_class,
1e691d
                                     PROP_EXPIRATION_TIMESTAMP,
1e691d
                                     "expiration-timestamp");
1e691d
 
1e691d
 }
1e691d
 
1e691d
 static char *
1e691d
 get_identifier (GoaKerberosIdentity  *self,
1e691d
                 GError              **error)
1e691d
 {
1e691d
   krb5_principal principal;
1e691d
   krb5_error_code error_code;
1e691d
   char *unparsed_name;
1e691d
   char *identifier = NULL;
1e691d
 
1e691d
   if (self->priv->credentials_cache == NULL)
1e691d
     return NULL;
1e691d
 
1e691d
   error_code = krb5_cc_get_principal (self->priv->kerberos_context,
1e691d
                                       self->priv->credentials_cache,
1e691d
                                       &principal);
1e691d
 
1e691d
   if (error_code != 0)
1e691d
     {
1e691d
       if (error_code == KRB5_CC_END)
1e691d
         {
1e691d
           set_error_from_krb5_error_code (self,
1e691d
                                           error,
1e691d
                                           GOA_IDENTITY_ERROR_CREDENTIALS_UNAVAILABLE,
1e691d
                                           error_code,
1e691d
                                           _
1e691d
@@ -546,207 +557,233 @@ on_notify_queued (NotifyRequest *request)
1e691d
 
1e691d
   return FALSE;
1e691d
 }
1e691d
 
1e691d
 static void
1e691d
 queue_notify (GoaKerberosIdentity *self,
1e691d
               guint               *idle_id,
1e691d
               const char          *property_name)
1e691d
 {
1e691d
   NotifyRequest *request;
1e691d
 
1e691d
   if (*idle_id != 0)
1e691d
     {
1e691d
       return;
1e691d
     }
1e691d
 
1e691d
   request = g_slice_new0 (NotifyRequest);
1e691d
   request->self = g_object_ref (self);
1e691d
   request->idle_id = idle_id;
1e691d
   request->property_name = property_name;
1e691d
 
1e691d
   *idle_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
1e691d
                               (GSourceFunc)
1e691d
                               on_notify_queued,
1e691d
                               request,
1e691d
                               (GDestroyNotify)
1e691d
                               clear_idle_id);
1e691d
 }
1e691d
 
1e691d
 static void
1e691d
+set_start_time (GoaKerberosIdentity *self,
1e691d
+                krb5_timestamp       start_time)
1e691d
+{
1e691d
+  G_LOCK (identity_lock);
1e691d
+  if (self->priv->start_time != start_time)
1e691d
+    {
1e691d
+      self->priv->start_time = start_time;
1e691d
+      G_UNLOCK (identity_lock);
1e691d
+      queue_notify (self,
1e691d
+                    &self->priv->start_time_idle_id,
1e691d
+                    "start-timestamp");
1e691d
+      G_LOCK (identity_lock);
1e691d
+    }
1e691d
+  G_UNLOCK (identity_lock);
1e691d
+}
1e691d
+
1e691d
+static void
1e691d
 set_expiration_time (GoaKerberosIdentity *self,
1e691d
                      krb5_timestamp       expiration_time)
1e691d
 {
1e691d
   G_LOCK (identity_lock);
1e691d
   if (self->priv->expiration_time != expiration_time)
1e691d
     {
1e691d
       self->priv->expiration_time = expiration_time;
1e691d
       G_UNLOCK (identity_lock);
1e691d
       queue_notify (self,
1e691d
                     &self->priv->expiration_time_idle_id,
1e691d
                     "expiration-timestamp");
1e691d
       G_LOCK (identity_lock);
1e691d
     }
1e691d
   G_UNLOCK (identity_lock);
1e691d
 }
1e691d
 
1e691d
 static gboolean
1e691d
 credentials_are_expired (GoaKerberosIdentity *self,
1e691d
                          krb5_creds          *credentials,
1e691d
+                         krb5_timestamp      *start_time,
1e691d
                          krb5_timestamp      *expiration_time)
1e691d
 {
1e691d
   krb5_timestamp current_time;
1e691d
 
1e691d
   current_time = get_current_time (self);
1e691d
 
1e691d
   G_LOCK (identity_lock);
1e691d
+  if (self->priv->start_time == 0)
1e691d
+    *start_time = credentials->times.starttime;
1e691d
+  else
1e691d
+    *start_time = MIN (self->priv->start_time,
1e691d
+                       credentials->times.starttime);
1e691d
   *expiration_time = MAX (credentials->times.endtime,
1e691d
                           self->priv->expiration_time);
1e691d
   G_UNLOCK (identity_lock);
1e691d
 
1e691d
-  if (credentials->times.endtime <= current_time)
1e691d
+  if (current_time < credentials->times.starttime ||
1e691d
+      credentials->times.endtime <= current_time)
1e691d
     {
1e691d
       return TRUE;
1e691d
     }
1e691d
 
1e691d
   return FALSE;
1e691d
 }
1e691d
 
1e691d
 static VerificationLevel
1e691d
 verify_identity (GoaKerberosIdentity  *self,
1e691d
                  char                **preauth_identity_source,
1e691d
                  GError              **error)
1e691d
 {
1e691d
   krb5_principal principal = NULL;
1e691d
   krb5_cc_cursor cursor;
1e691d
   krb5_creds credentials;
1e691d
   krb5_error_code error_code;
1e691d
+  krb5_timestamp start_time = 0;
1e691d
   krb5_timestamp expiration_time = 0;
1e691d
   VerificationLevel verification_level = VERIFICATION_LEVEL_UNVERIFIED;
1e691d
 
1e691d
   if (self->priv->credentials_cache == NULL)
1e691d
     goto out;
1e691d
 
1e691d
   error_code = krb5_cc_get_principal (self->priv->kerberos_context,
1e691d
                                       self->priv->credentials_cache,
1e691d
                                       &principal);
1e691d
 
1e691d
   if (error_code != 0)
1e691d
     {
1e691d
       if (error_code == KRB5_CC_END || error_code == KRB5_FCC_NOFILE)
1e691d
         goto out;
1e691d
 
1e691d
       set_error_from_krb5_error_code (self,
1e691d
                                       error,
1e691d
                                       GOA_IDENTITY_ERROR_NOT_FOUND,
1e691d
                                       error_code,
1e691d
                                       _("Could not find identity in "
1e691d
                                         "credential cache: %k"));
1e691d
       verification_level = VERIFICATION_LEVEL_ERROR;
1e691d
       goto out;
1e691d
     }
1e691d
 
1e691d
   error_code = krb5_cc_start_seq_get (self->priv->kerberos_context,
1e691d
                                       self->priv->credentials_cache, &cursor);
1e691d
   if (error_code != 0)
1e691d
     {
1e691d
       set_error_from_krb5_error_code (self,
1e691d
                                       error,
1e691d
                                       GOA_IDENTITY_ERROR_CREDENTIALS_UNAVAILABLE,
1e691d
                                       error_code,
1e691d
                                       _("Could not find identity "
1e691d
                                         "credentials in cache: %k"));
1e691d
 
1e691d
       verification_level = VERIFICATION_LEVEL_ERROR;
1e691d
       goto out;
1e691d
     }
1e691d
 
1e691d
   verification_level = VERIFICATION_LEVEL_UNVERIFIED;
1e691d
 
1e691d
   error_code = krb5_cc_next_cred (self->priv->kerberos_context,
1e691d
                                   self->priv->credentials_cache,
1e691d
                                   &cursor,
1e691d
                                   &credentials);
1e691d
 
1e691d
   while (error_code == 0)
1e691d
     {
1e691d
       if (credentials_validate_existence (self, principal, &credentials))
1e691d
         {
1e691d
-          if (!credentials_are_expired (self, &credentials, &expiration_time))
1e691d
+          if (!credentials_are_expired (self, &credentials, &start_time, &expiration_time))
1e691d
             verification_level = VERIFICATION_LEVEL_SIGNED_IN;
1e691d
           else
1e691d
             verification_level = VERIFICATION_LEVEL_EXISTS;
1e691d
         }
1e691d
       else
1e691d
         {
1e691d
           snoop_preauth_identity_from_credentials (self, &credentials, preauth_identity_source);
1e691d
         }
1e691d
 
1e691d
       krb5_free_cred_contents (self->priv->kerberos_context, &credentials);
1e691d
 
1e691d
       error_code = krb5_cc_next_cred (self->priv->kerberos_context,
1e691d
                                       self->priv->credentials_cache,
1e691d
                                       &cursor,
1e691d
                                       &credentials);
1e691d
     }
1e691d
 
1e691d
   if (error_code != KRB5_CC_END)
1e691d
     {
1e691d
       verification_level = VERIFICATION_LEVEL_ERROR;
1e691d
 
1e691d
       set_error_from_krb5_error_code (self,
1e691d
                                       error,
1e691d
                                       GOA_IDENTITY_ERROR_ENUMERATING_CREDENTIALS,
1e691d
                                       error_code,
1e691d
                                       _("Could not sift through identity "
1e691d
                                         "credentials in cache: %k"));
1e691d
       goto end_sequence;
1e691d
     }
1e691d
 
1e691d
  end_sequence:
1e691d
   error_code = krb5_cc_end_seq_get (self->priv->kerberos_context,
1e691d
                                     self->priv->credentials_cache,
1e691d
                                     &cursor);
1e691d
 
1e691d
   if (error_code != 0)
1e691d
     {
1e691d
       verification_level = VERIFICATION_LEVEL_ERROR;
1e691d
 
1e691d
       set_error_from_krb5_error_code (self,
1e691d
                                       error,
1e691d
                                       GOA_IDENTITY_ERROR_ENUMERATING_CREDENTIALS,
1e691d
                                       error_code,
1e691d
                                       _("Could not finish up sifting through "
1e691d
                                         "identity credentials in cache: %k"));
1e691d
       goto out;
1e691d
     }
1e691d
 out:
1e691d
+  set_start_time (self, start_time);
1e691d
   set_expiration_time (self, expiration_time);
1e691d
 
1e691d
   if (principal != NULL)
1e691d
     krb5_free_principal (self->priv->kerberos_context, principal);
1e691d
   return verification_level;
1e691d
 }
1e691d
 
1e691d
 static gboolean
1e691d
 goa_kerberos_identity_is_signed_in (GoaIdentity *identity)
1e691d
 {
1e691d
   GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (identity);
1e691d
   gboolean is_signed_in = FALSE;
1e691d
 
1e691d
   G_LOCK (identity_lock);
1e691d
   if (self->priv->cached_verification_level == VERIFICATION_LEVEL_SIGNED_IN)
1e691d
     is_signed_in = TRUE;
1e691d
   G_UNLOCK (identity_lock);
1e691d
 
1e691d
   return is_signed_in;
1e691d
 }
1e691d
 
1e691d
 static void
1e691d
 identity_interface_init (GoaIdentityInterface *interface)
1e691d
 {
1e691d
   interface->get_identifier = goa_kerberos_identity_get_identifier;
1e691d
   interface->is_signed_in = goa_kerberos_identity_is_signed_in;
1e691d
 }
1e691d
 
1e691d
 static void
1e691d
 on_expiration_alarm_fired (GoaAlarm            *alarm,
1e691d
@@ -895,90 +932,90 @@ connect_alarm_signals (GoaKerberosIdentity *self)
1e691d
 {
1e691d
   g_signal_connect (G_OBJECT (self->priv->renewal_alarm),
1e691d
                     "fired",
1e691d
                     G_CALLBACK (on_renewal_alarm_fired),
1e691d
                     self);
1e691d
   g_signal_connect (G_OBJECT (self->priv->renewal_alarm),
1e691d
                     "rearmed",
1e691d
                     G_CALLBACK (on_renewal_alarm_rearmed),
1e691d
                     self);
1e691d
   g_signal_connect (G_OBJECT (self->priv->expiring_alarm),
1e691d
                     "fired",
1e691d
                     G_CALLBACK (on_expiring_alarm_fired),
1e691d
                     self);
1e691d
   g_signal_connect (G_OBJECT (self->priv->expiring_alarm),
1e691d
                     "rearmed",
1e691d
                     G_CALLBACK (on_expiring_alarm_rearmed),
1e691d
                     self);
1e691d
   g_signal_connect (G_OBJECT (self->priv->expiration_alarm),
1e691d
                     "fired",
1e691d
                     G_CALLBACK (on_expiration_alarm_fired),
1e691d
                     self);
1e691d
   g_signal_connect (G_OBJECT (self->priv->expiration_alarm),
1e691d
                     "rearmed",
1e691d
                     G_CALLBACK (on_expiration_alarm_rearmed),
1e691d
                     self);
1e691d
 }
1e691d
 
1e691d
 static void
1e691d
 reset_alarms (GoaKerberosIdentity *self)
1e691d
 {
1e691d
-  GDateTime *now;
1e691d
+  GDateTime *start_time;
1e691d
   GDateTime *expiration_time;
1e691d
   GDateTime *expiring_time;
1e691d
   GDateTime *renewal_time;
1e691d
-  GTimeSpan time_span_until_expiration;
1e691d
+  GTimeSpan  lifespan;
1e691d
 
1e691d
-  now = g_date_time_new_now_local ();
1e691d
   G_LOCK (identity_lock);
1e691d
+  start_time = g_date_time_new_from_unix_local (self->priv->start_time);
1e691d
   expiration_time = g_date_time_new_from_unix_local (self->priv->expiration_time);
1e691d
   G_UNLOCK (identity_lock);
1e691d
-  time_span_until_expiration = g_date_time_difference (expiration_time, now);
1e691d
-  g_date_time_unref (now);
1e691d
+
1e691d
+  lifespan = g_date_time_difference (expiration_time, start_time);
1e691d
 
1e691d
   /* Let the user reauthenticate 10 min before expiration */
1e691d
   expiring_time = g_date_time_add_minutes (expiration_time, -10);
1e691d
 
1e691d
   /* Try to quietly auto-renew halfway through so in ideal configurations
1e691d
    * the ticket is never more than halfway to expired
1e691d
    */
1e691d
-  renewal_time = g_date_time_add (expiration_time,
1e691d
-                                  -(time_span_until_expiration / 2));
1e691d
+  renewal_time = g_date_time_add (expiration_time, -(lifespan / 2));
1e691d
 
1e691d
   disconnect_alarm_signals (self);
1e691d
 
1e691d
   reset_alarm (self, &self->priv->renewal_alarm, renewal_time);
1e691d
   reset_alarm (self, &self->priv->expiring_alarm, expiring_time);
1e691d
   reset_alarm (self, &self->priv->expiration_alarm, expiration_time);
1e691d
 
1e691d
   g_date_time_unref (renewal_time);
1e691d
   g_date_time_unref (expiring_time);
1e691d
+  g_date_time_unref (start_time);
1e691d
   g_date_time_unref (expiration_time);
1e691d
   connect_alarm_signals (self);
1e691d
 }
1e691d
 
1e691d
 static void
1e691d
 clear_alarms (GoaKerberosIdentity *self)
1e691d
 {
1e691d
   disconnect_alarm_signals (self);
1e691d
   clear_alarm_and_unref_on_idle (self, &self->priv->renewal_alarm);
1e691d
   clear_alarm_and_unref_on_idle (self, &self->priv->expiring_alarm);
1e691d
   clear_alarm_and_unref_on_idle (self, &self->priv->expiration_alarm);
1e691d
 }
1e691d
 
1e691d
 static gboolean
1e691d
 goa_kerberos_identity_initable_init (GInitable     *initable,
1e691d
                                      GCancellable  *cancellable,
1e691d
                                      GError       **error)
1e691d
 {
1e691d
   GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (initable);
1e691d
   GError *verification_error;
1e691d
 
1e691d
   if (g_cancellable_set_error_if_cancelled (cancellable, error))
1e691d
     return FALSE;
1e691d
 
1e691d
   if (self->priv->identifier == NULL)
1e691d
     {
1e691d
       self->priv->identifier = get_identifier (self, error);
1e691d
 
1e691d
       if (self->priv->identifier != NULL)
1e691d
         queue_notify (self, &self->priv->identifier_idle_id, "identifier");
1e691d
-- 
1e691d
2.5.0
1e691d
1e691d
1e691d
From 57757628e01dcd1d6ce9855bdad70d5f69757157 Mon Sep 17 00:00:00 2001
1e691d
From: Ray Strode <rstrode@redhat.com>
1e691d
Date: Tue, 22 Sep 2015 14:41:05 -0400
1e691d
Subject: [PATCH 2/3] identity: don't ever nullify identifier
1e691d
1e691d
credentials stored in the kernel keyring disappear after they expire.
1e691d
This is is different from other credential caches, which hang around
1e691d
but maintain an expired timestamp until kdestroy. Because the credentials
1e691d
vanish, trying to read the principal from an previously existing credential
1e691d
cache, will yield NULL.
1e691d
1e691d
This can lead to a crash in goa which never expects the identifier of an
1e691d
identity object to be NULL.
1e691d
1e691d
This commit makes sure we retain the old identifier in the event the
1e691d
credential cache gets wiped.
1e691d
---
1e691d
 src/goaidentity/goakerberosidentity.c | 2 +-
1e691d
 1 file changed, 1 insertion(+), 1 deletion(-)
1e691d
1e691d
diff --git a/src/goaidentity/goakerberosidentity.c b/src/goaidentity/goakerberosidentity.c
1e691d
index 6865535..f43978d 100644
1e691d
--- a/src/goaidentity/goakerberosidentity.c
1e691d
+++ b/src/goaidentity/goakerberosidentity.c
1e691d
@@ -1355,61 +1355,61 @@ goa_kerberos_identity_sign_in (GoaKerberosIdentity     *self,
1e691d
       goto done;
1e691d
     }
1e691d
 
1e691d
   if (destroy_notify)
1e691d
     destroy_notify (inquiry_data);
1e691d
   sign_in_operation_free (operation);
1e691d
 
1e691d
   if (!goa_kerberos_identity_update_credentials (self,
1e691d
                                                  principal,
1e691d
                                                  &new_credentials,
1e691d
                                                  error))
1e691d
     {
1e691d
       krb5_free_principal (self->priv->kerberos_context, principal);
1e691d
       goto done;
1e691d
     }
1e691d
   krb5_free_principal (self->priv->kerberos_context, principal);
1e691d
 
1e691d
   g_debug ("GoaKerberosIdentity: identity signed in");
1e691d
   signed_in = TRUE;
1e691d
 done:
1e691d
 
1e691d
   return signed_in;
1e691d
 }
1e691d
 
1e691d
 static void
1e691d
 update_identifier (GoaKerberosIdentity *self, GoaKerberosIdentity *new_identity)
1e691d
 {
1e691d
   char *new_identifier;
1e691d
 
1e691d
   new_identifier = get_identifier (self, NULL);
1e691d
-  if (g_strcmp0 (self->priv->identifier, new_identifier) != 0)
1e691d
+  if (g_strcmp0 (self->priv->identifier, new_identifier) != 0 && new_identifier != NULL)
1e691d
     {
1e691d
       g_free (self->priv->identifier);
1e691d
       self->priv->identifier = new_identifier;
1e691d
       queue_notify (self, &self->priv->identifier_idle_id, "identifier");
1e691d
     }
1e691d
   else
1e691d
     {
1e691d
       g_free (new_identifier);
1e691d
     }
1e691d
 }
1e691d
 
1e691d
 void
1e691d
 goa_kerberos_identity_update (GoaKerberosIdentity *self,
1e691d
                               GoaKerberosIdentity *new_identity)
1e691d
 {
1e691d
   VerificationLevel verification_level;
1e691d
   char *preauth_identity_source = NULL;
1e691d
 
1e691d
   if (self->priv->credentials_cache != NULL)
1e691d
     krb5_cc_close (self->priv->kerberos_context, self->priv->credentials_cache);
1e691d
 
1e691d
   krb5_cc_dup (new_identity->priv->kerberos_context,
1e691d
                new_identity->priv->credentials_cache,
1e691d
                &self->priv->credentials_cache);
1e691d
 
1e691d
   G_LOCK (identity_lock);
1e691d
   update_identifier (self, new_identity);
1e691d
   G_UNLOCK (identity_lock);
1e691d
 
1e691d
   verification_level = verify_identity (self, &preauth_identity_source, NULL);
1e691d
-- 
1e691d
2.5.0
1e691d
1e691d
1e691d
From 8d8a923530402fef8dd04b5b4efd349c45118e13 Mon Sep 17 00:00:00 2001
1e691d
From: Ray Strode <rstrode@redhat.com>
1e691d
Date: Tue, 22 Sep 2015 14:38:29 -0400
1e691d
Subject: [PATCH 3/3] identity: don't ignore almost all renewal requests
1e691d
1e691d
There's a bug in the code where we ignore all renewal requests for
1e691d
objects we already know about.
1e691d
1e691d
This means we'll only ever honor renewal requests that happen almost
1e691d
immediately after start up.
1e691d
1e691d
This commit fixes the bug, so the only renewal requests that aren't
1e691d
honored, are those that have been specifically disabled by the user.
1e691d
This was clearly the original intention of the buggy code.
1e691d
---
1e691d
 src/goaidentity/goaidentityservice.c | 9 +++++----
1e691d
 1 file changed, 5 insertions(+), 4 deletions(-)
1e691d
1e691d
diff --git a/src/goaidentity/goaidentityservice.c b/src/goaidentity/goaidentityservice.c
1e691d
index 6b6225a..bb5d3a7 100644
1e691d
--- a/src/goaidentity/goaidentityservice.c
1e691d
+++ b/src/goaidentity/goaidentityservice.c
1e691d
@@ -714,70 +714,71 @@ static void
1e691d
 on_identity_renewed (GoaIdentityManager *manager,
1e691d
                      GAsyncResult       *result,
1e691d
                      GoaIdentityService *self)
1e691d
 {
1e691d
   GError *error;
1e691d
 
1e691d
   error = NULL;
1e691d
   goa_identity_manager_renew_identity_finish (manager, result, &error);
1e691d
 
1e691d
   if (error != NULL)
1e691d
     {
1e691d
       g_debug ("GoaIdentityService: could not renew identity: %s",
1e691d
                error->message);
1e691d
       g_error_free (error);
1e691d
       return;
1e691d
     }
1e691d
 
1e691d
   g_debug ("GoaIdentityService: identity renewed");
1e691d
 }
1e691d
 
1e691d
 static void
1e691d
 on_identity_needs_renewal (GoaIdentityManager *identity_manager,
1e691d
                            GoaIdentity        *identity,
1e691d
                            GoaIdentityService *self)
1e691d
 {
1e691d
   const char *principal;
1e691d
   GoaObject  *object;
1e691d
 
1e691d
   principal = goa_identity_get_identifier (identity);
1e691d
 
1e691d
-  g_debug ("GoaIdentityService: identity %s needs renewal", principal);
1e691d
-
1e691d
   object = find_object_with_principal (self, principal, TRUE);
1e691d
 
1e691d
-  if (object != NULL)
1e691d
+  if (object != NULL && should_ignore_object (self, object))
1e691d
     {
1e691d
-      should_ignore_object (self, object);
1e691d
+      g_debug ("GoaIdentityService: ignoring identity %s that says it needs renewal", principal);
1e691d
+
1e691d
       return;
1e691d
     }
1e691d
 
1e691d
+  g_debug ("GoaIdentityService: identity %s needs renewal", principal);
1e691d
+
1e691d
   goa_identity_manager_renew_identity (GOA_IDENTITY_MANAGER
1e691d
                                        (self->priv->identity_manager),
1e691d
                                        identity,
1e691d
                                        NULL,
1e691d
                                        (GAsyncReadyCallback)
1e691d
                                        on_identity_renewed,
1e691d
                                        self);
1e691d
 }
1e691d
 
1e691d
 static void
1e691d
 on_identity_signed_in (GoaIdentityManager *manager,
1e691d
                        GAsyncResult       *result,
1e691d
                        GSimpleAsyncResult *operation_result)
1e691d
 {
1e691d
   GError *error;
1e691d
   GoaIdentity *identity;
1e691d
 
1e691d
   error = NULL;
1e691d
   identity = goa_identity_manager_sign_identity_in_finish (manager, result, &error);
1e691d
 
1e691d
   if (error != NULL)
1e691d
     {
1e691d
       g_debug ("GoaIdentityService: could not sign in identity: %s",
1e691d
                error->message);
1e691d
       g_simple_async_result_take_error (operation_result, error);
1e691d
     }
1e691d
   else
1e691d
     {
1e691d
       g_simple_async_result_set_op_res_gpointer (operation_result,
1e691d
                                                  g_object_ref (identity),
1e691d
-- 
1e691d
2.5.0
1e691d