[gnome-keyring/wip/dueno/ssh-agent-2: 3/7] login: Add GkdLoginInteraction API
- From: Daiki Ueno <dueno src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-keyring/wip/dueno/ssh-agent-2: 3/7] login: Add GkdLoginInteraction API
- Date: Mon, 19 Feb 2018 17:24:40 +0000 (UTC)
commit af0a2c13db04d24d659f22bf8d87b330c23cae62
Author: Daiki Ueno <dueno src gnome org>
Date: Fri Feb 16 14:04:09 2018 +0100
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
daemon/login/Makefile.am | 4 +
daemon/login/gkd-login-interaction.c | 273 ++++++++++++++++++++++++++++++++++
daemon/login/gkd-login-interaction.h | 36 +++++
daemon/login/gkd-login-password.c | 142 ++++++++++++++++++
daemon/login/gkd-login-password.h | 38 +++++
5 files changed, 493 insertions(+), 0 deletions(-)
---
diff --git a/daemon/login/Makefile.am b/daemon/login/Makefile.am
index 2b6d389..3bf6b9c 100644
--- a/daemon/login/Makefile.am
+++ b/daemon/login/Makefile.am
@@ -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) \
diff --git a/daemon/login/gkd-login-interaction.c b/daemon/login/gkd-login-interaction.c
new file mode 100644
index 0000000..00c9d78
--- /dev/null
+++ b/daemon/login/gkd-login-interaction.c
@@ -0,0 +1,273 @@
+/* gkd-login-interaction.c
+
+ Copyright (C) 2018 Daiki Ueno
+
+ The Gnome Keyring Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Keyring Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. 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)
+ 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);
+
+ /* egg_secure_strndup() doesn't null-terminate the result */
+ password = egg_secure_alloc (length + 1);
+ memcpy (password, (const gchar *)value, length);
+ password[length] = '\0';
+ 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);
+}
diff --git a/daemon/login/gkd-login-interaction.h b/daemon/login/gkd-login-interaction.h
new file mode 100644
index 0000000..330e528
--- /dev/null
+++ b/daemon/login/gkd-login-interaction.h
@@ -0,0 +1,36 @@
+/* gkd-login-interaction.h
+
+ Copyright (C) 2018 Daiki Ueno
+
+ The Gnome Keyring Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Keyring Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. 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__ */
diff --git a/daemon/login/gkd-login-password.c b/daemon/login/gkd-login-password.c
new file mode 100644
index 0000000..0fc3ec0
--- /dev/null
+++ b/daemon/login/gkd-login-password.c
@@ -0,0 +1,142 @@
+/* gkd-login-interaction.c
+
+ Copyright (C) 2018 Daiki Ueno
+
+ The Gnome Keyring Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Keyring Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. 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;
+}
diff --git a/daemon/login/gkd-login-password.h b/daemon/login/gkd-login-password.h
new file mode 100644
index 0000000..e91971a
--- /dev/null
+++ b/daemon/login/gkd-login-password.h
@@ -0,0 +1,38 @@
+/* gkd-login-password.h
+
+ Copyright (C) 2018 Daiki Ueno
+
+ The Gnome Keyring Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Keyring Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. 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__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]