Commit 66288946 authored by Daiki Ueno's avatar Daiki Ueno

login: Add GkdLoginInteraction API

This decorates underlying GTlsInteraction with a capability of
retrieving/storing passwords in the login keyring.

https://bugzilla.gnome.org/show_bug.cgi?id=775981
parent 5f7ab25b
......@@ -7,6 +7,10 @@ noinst_LTLIBRARIES += libgkd-login.la
libgkd_login_la_SOURCES = \
daemon/login/gkd-login.c \
daemon/login/gkd-login.h \
daemon/login/gkd-login-interaction.c \
daemon/login/gkd-login-interaction.h \
daemon/login/gkd-login-password.c \
daemon/login/gkd-login-password.h \
$(NULL)
libgkd_login_la_CFLAGS = \
$(GCK_CFLAGS) \
......
/*
* gnome-keyring
*
* Copyright (C) 2018 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see
* <http://www.gnu.org/licenses/>.
*
* Author: Daiki Ueno
*/
#include "config.h"
#include "gkd-login-interaction.h"
#include "gkd-login-password.h"
#include <gcr/gcr-unlock-options.h>
#include "gkd-login.h"
#include "egg/egg-secure-memory.h"
#include <string.h>
enum {
PROP_0,
PROP_BASE,
PROP_SESSION,
PROP_LABEL,
PROP_FIELDS
};
struct _GkdLoginInteraction
{
GTlsInteraction interaction;
GTlsInteraction *base;
GckSession *session;
gchar *label;
GHashTable *fields;
gboolean login_available;
};
G_DEFINE_TYPE (GkdLoginInteraction, gkd_login_interaction, G_TYPE_TLS_INTERACTION);
EGG_SECURE_DECLARE (gkd_login_interaction);
static void
gkd_login_interaction_init (GkdLoginInteraction *self)
{
}
static void
gkd_login_interaction_constructed (GObject *object)
{
GkdLoginInteraction *self = GKD_LOGIN_INTERACTION (object);
self->login_available = gkd_login_available (self->session);
G_OBJECT_CLASS (gkd_login_interaction_parent_class)->constructed (object);
}
static GkdLoginPassword *
wrap_password (GkdLoginInteraction *self,
GTlsPassword *password)
{
GkdLoginPassword *wrapped;
wrapped = g_object_new (GKD_TYPE_LOGIN_PASSWORD,
"base", password,
"login-available", self->login_available,
NULL);
g_tls_password_set_description (G_TLS_PASSWORD (wrapped), self->label);
return wrapped;
}
static void
on_ask_password_ready (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GTask *task = G_TASK (user_data);
GkdLoginInteraction *self = g_task_get_source_object (task);
GTlsInteractionResult result;
GError *error = NULL;
result = g_tls_interaction_ask_password_finish (self->base, res, &error);
if (result == G_TLS_INTERACTION_FAILED && error != NULL)
g_task_return_error (task, error);
else
g_task_return_int (task, result);
g_object_unref (task);
}
static void
gkd_login_interaction_ask_password_async (GTlsInteraction *interaction,
GTlsPassword *password,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GkdLoginInteraction *self = GKD_LOGIN_INTERACTION (interaction);
GkdLoginPassword *login_password;
GTask *task;
login_password = wrap_password (self, password);
task = g_task_new (interaction, cancellable, callback, user_data);
g_task_set_task_data (task, g_object_ref (login_password), g_object_unref);
/* If the login keyring is available, look for the password there */
if (self->login_available) {
gchar *value = gkd_login_lookup_passwordv (self->session, self->fields);
if (value) {
g_tls_password_set_value_full (G_TLS_PASSWORD (login_password), (guchar *)value, strlen (value), (GDestroyNotify)egg_secure_free);
g_object_unref (login_password);
g_task_return_int (task, G_TLS_INTERACTION_HANDLED);
g_object_unref (task);
return;
}
}
/* Otherwise, call out to the base interaction */
g_tls_interaction_ask_password_async (self->base,
G_TLS_PASSWORD (login_password),
cancellable,
on_ask_password_ready,
task);
g_object_unref (login_password);
}
static GTlsInteractionResult
gkd_login_interaction_ask_password_finish (GTlsInteraction *interaction,
GAsyncResult *res,
GError **error)
{
GkdLoginInteraction *self = GKD_LOGIN_INTERACTION (interaction);
GTask *task = G_TASK (res);
GkdLoginPassword *login_password = g_task_get_task_data (task);
GTlsInteractionResult result;
result = g_task_propagate_int (task, error);
if (result == -1)
result = G_TLS_INTERACTION_FAILED;
if (self->login_available &&
result == G_TLS_INTERACTION_HANDLED &&
gkd_login_password_get_store_password (login_password)) {
const guchar *value;
gsize length;
gchar *password;
value = g_tls_password_get_value (G_TLS_PASSWORD (login_password),
&length);
password = egg_secure_strndup ((const gchar *)value, length);
gkd_login_store_passwordv (self->session,
password,
self->label,
GCR_UNLOCK_OPTION_ALWAYS, -1,
self->fields);
egg_secure_free (password);
}
return result;
}
static void
gkd_login_interaction_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GkdLoginInteraction *self = GKD_LOGIN_INTERACTION (object);
switch (prop_id)
{
case PROP_BASE:
self->base = g_value_dup_object (value);
break;
case PROP_SESSION:
self->session = g_value_dup_object (value);
break;
case PROP_LABEL:
self->label = g_value_dup_string (value);
break;
case PROP_FIELDS:
self->fields = g_value_dup_boxed (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gkd_login_interaction_dispose (GObject *object)
{
GkdLoginInteraction *self = GKD_LOGIN_INTERACTION (object);
g_clear_object (&self->base);
g_clear_object (&self->session);
G_OBJECT_CLASS (gkd_login_interaction_parent_class)->dispose (object);
}
static void
gkd_login_interaction_finalize (GObject *object)
{
GkdLoginInteraction *self = GKD_LOGIN_INTERACTION (object);
g_free (self->label);
g_hash_table_unref (self->fields);
G_OBJECT_CLASS (gkd_login_interaction_parent_class)->finalize (object);
}
static void
gkd_login_interaction_class_init (GkdLoginInteractionClass *klass)
{
GTlsInteractionClass *interaction_class = G_TLS_INTERACTION_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
interaction_class->ask_password_async = gkd_login_interaction_ask_password_async;
interaction_class->ask_password_finish = gkd_login_interaction_ask_password_finish;
gobject_class->constructed = gkd_login_interaction_constructed;
gobject_class->set_property = gkd_login_interaction_set_property;
gobject_class->dispose = gkd_login_interaction_dispose;
gobject_class->finalize = gkd_login_interaction_finalize;
g_object_class_install_property (gobject_class, PROP_BASE,
g_param_spec_object ("base", "Base", "Base",
G_TYPE_TLS_INTERACTION,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
g_object_class_install_property (gobject_class, PROP_SESSION,
g_param_spec_object ("session", "Session", "Session",
GCK_TYPE_SESSION,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
g_object_class_install_property (gobject_class, PROP_LABEL,
g_param_spec_string ("label", "Label", "Label",
"",
G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
g_object_class_install_property (gobject_class, PROP_FIELDS,
g_param_spec_boxed ("fields", "Fields", "Fields",
G_TYPE_HASH_TABLE,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
}
GTlsInteraction *
gkd_login_interaction_new (GTlsInteraction *base,
GckSession *session,
const gchar *label,
GHashTable *fields)
{
return g_object_new (GKD_TYPE_LOGIN_INTERACTION,
"base", base,
"session", session,
"label", label,
"fields", fields,
NULL);
}
/*
* gnome-keyring
*
* Copyright (C) 2018 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see
* <http://www.gnu.org/licenses/>.
*
* Author: Daiki Ueno
*/
#ifndef __GKD_LOGIN_INTERACTION_H__
#define __GKD_LOGIN_INTERACTION_H__
#include <gio/gio.h>
#include <gck/gck.h>
#define GKD_TYPE_LOGIN_INTERACTION gkd_login_interaction_get_type ()
G_DECLARE_FINAL_TYPE (GkdLoginInteraction, gkd_login_interaction, GKD, LOGIN_INTERACTION, GTlsInteraction);
GTlsInteraction *gkd_login_interaction_new (GTlsInteraction *base,
GckSession *session,
const gchar *label,
GHashTable *fields);
#endif /* __GKD_LOGIN_INTERACTION_H__ */
/*
* gnome-keyring
*
* Copyright (C) 2018 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see
* <http://www.gnu.org/licenses/>.
*
* Author: Daiki Ueno
*/
#include "config.h"
#include "gkd-login-password.h"
#include <gcr/gcr-unlock-options.h>
#include "gkd-login.h"
enum {
PROP_0,
PROP_BASE,
PROP_LOGIN_AVAILABLE
};
struct _GkdLoginPassword
{
GTlsPassword password;
GTlsPassword *base;
gboolean login_available;
gboolean store_password;
};
G_DEFINE_TYPE (GkdLoginPassword, gkd_login_password, G_TYPE_TLS_PASSWORD);
static void
gkd_login_password_init (GkdLoginPassword *self)
{
}
static const guchar *
gkd_login_password_get_value (GTlsPassword *password,
gsize *length)
{
GkdLoginPassword *self = GKD_LOGIN_PASSWORD (password);
return g_tls_password_get_value (self->base, length);
}
static void
gkd_login_password_set_value (GTlsPassword *password,
guchar *value,
gssize length,
GDestroyNotify destroy)
{
GkdLoginPassword *self = GKD_LOGIN_PASSWORD (password);
g_tls_password_set_value_full (self->base, value, length, destroy);
}
static void
gkd_login_password_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GkdLoginPassword *self = GKD_LOGIN_PASSWORD (object);
switch (prop_id)
{
case PROP_BASE:
self->base = g_value_dup_object (value);
break;
case PROP_LOGIN_AVAILABLE:
self->login_available = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gkd_login_password_dispose (GObject *object)
{
GkdLoginPassword *self = GKD_LOGIN_PASSWORD (object);
g_clear_object (&self->base);
G_OBJECT_CLASS (gkd_login_password_parent_class)->dispose (object);
}
static void
gkd_login_password_class_init (GkdLoginPasswordClass *klass)
{
GTlsPasswordClass *password_class = G_TLS_PASSWORD_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
password_class->get_value = gkd_login_password_get_value;
password_class->set_value = gkd_login_password_set_value;
gobject_class->set_property = gkd_login_password_set_property;
gobject_class->dispose = gkd_login_password_dispose;
g_object_class_install_property (gobject_class, PROP_BASE,
g_param_spec_object ("base", "Base", "Base",
G_TYPE_TLS_PASSWORD,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
g_object_class_install_property (gobject_class, PROP_LOGIN_AVAILABLE,
g_param_spec_boolean ("login-available", "Login-available", "Login-available",
FALSE,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
}
gboolean
gkd_login_password_get_login_available (GkdLoginPassword *self)
{
return self->login_available;
}
void
gkd_login_password_set_store_password (GkdLoginPassword *self,
gboolean store_password)
{
self->store_password = store_password;
}
gboolean
gkd_login_password_get_store_password (GkdLoginPassword *self)
{
return self->store_password;
}
/*
* gnome-keyring
*
* Copyright (C) 2018 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see
* <http://www.gnu.org/licenses/>.
*
* Author: Daiki Ueno
*/
#ifndef __GKD_LOGIN_PASSWORD_H__
#define __GKD_LOGIN_PASSWORD_H__
#include <gio/gio.h>
#define GKD_TYPE_LOGIN_PASSWORD gkd_login_password_get_type ()
G_DECLARE_FINAL_TYPE (GkdLoginPassword, gkd_login_password, GKD, LOGIN_PASSWORD, GTlsPassword);
gboolean gkd_login_password_get_login_available
(GkdLoginPassword *self);
void gkd_login_password_set_store_password
(GkdLoginPassword *self,
gboolean store_password);
gboolean gkd_login_password_get_store_password
(GkdLoginPassword *self);
#endif /* __GKD_LOGIN_PASSWORD_H__ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment