[gnome-keyring/wip/dueno/ssh-agent-2: 1/5] login: Add GkdLoginInteraction API



commit 00cc1befd646f1e4a9610ebf2e936b08f081e9d0
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]