|
|
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 |
|