[gnome-keyring/wip/dueno/secret-portal] dbus: Implement secret portal backend
- From: Daiki Ueno <dueno src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-keyring/wip/dueno/secret-portal] dbus: Implement secret portal backend
- Date: Thu, 8 Aug 2019 16:02:06 +0000 (UTC)
commit 8e7c29c0cb055606d430a02a914115207f1f0871
Author: Daiki Ueno <dueno src gnome org>
Date: Sat Jul 27 05:36:41 2019 +0200
dbus: Implement secret portal backend
daemon/dbus/Makefile.am | 26 ++-
daemon/dbus/gkd-secret-service.c | 190 +++++++++++++++++++++
.../dbus/org.freedesktop.impl.portal.Request.xml | 47 +++++
daemon/dbus/org.freedesktop.impl.portal.Secret.xml | 65 +++++++
4 files changed, 327 insertions(+), 1 deletion(-)
---
diff --git a/daemon/dbus/Makefile.am b/daemon/dbus/Makefile.am
index 9d0b2e1a..13ad3b0b 100644
--- a/daemon/dbus/Makefile.am
+++ b/daemon/dbus/Makefile.am
@@ -32,10 +32,30 @@ daemon/dbus/gkd-internal-generated.h: daemon/dbus/org.gnome.keyring.InternalUnsu
daemon/dbus/gkd-internal-generated.c: daemon/dbus/gkd-internal-generated.h
@: # generated as a side-effect
+daemon/dbus/gkd-portal-generated.h: daemon/dbus/org.freedesktop.impl.portal.Secret.xml
+ $(AM_V_GEN) gdbus-codegen --interface-prefix org.freedesktop.impl.portal.Secret. \
+ --generate-c-code $(srcdir)/daemon/dbus/gkd-portal-generated \
+ --c-namespace Gkd \
+ --annotate "org.freedesktop.impl.portal.Secret" "org.gtk.GDBus.C.Name" ExportedPortal \
+ $(srcdir)/daemon/dbus/org.freedesktop.impl.portal.Secret.xml
+daemon/dbus/gkd-portal-generated.c: daemon/dbus/gkd-portal-generated.h
+ @: # generated as a side-effect
+
+daemon/dbus/gkd-portal-request-generated.h: daemon/dbus/org.freedesktop.impl.portal.Request.xml
+ $(AM_V_GEN) gdbus-codegen --interface-prefix org.freedesktop.impl.portal.Request. \
+ --generate-c-code $(srcdir)/daemon/dbus/gkd-portal-request-generated \
+ --c-namespace Gkd \
+ --annotate "org.freedesktop.impl.portal.Request" "org.gtk.GDBus.C.Name" ExportedPortalRequest \
+ $(srcdir)/daemon/dbus/org.freedesktop.impl.portal.Request.xml
+daemon/dbus/gkd-portal-request-generated.c: daemon/dbus/gkd-portal-request-generated.h
+ @: # generated as a side-effect
+
EXTRA_DIST += \
daemon/dbus/org.freedesktop.Secrets.xml \
daemon/dbus/org.gnome.keyring.Daemon.xml \
daemon/dbus/org.gnome.keyring.InternalUnsupportedGuiltRiddenInterface.xml \
+ daemon/dbus/org.freedesktop.impl.portal.Secret.xml \
+ daemon/dbus/org.freedesktop.impl.portal.Request.xml \
$(NULL)
BUILT_SOURCES += \
@@ -44,7 +64,11 @@ BUILT_SOURCES += \
daemon/dbus/gkd-internal-generated.c \
daemon/dbus/gkd-internal-generated.h \
daemon/dbus/gkd-secrets-generated.c \
- daemon/dbus/gkd-secrets-generated.h
+ daemon/dbus/gkd-secrets-generated.h \
+ daemon/dbus/gkd-portal-generated.c \
+ daemon/dbus/gkd-portal-generated.h \
+ daemon/dbus/gkd-portal-request-generated.c \
+ daemon/dbus/gkd-portal-request-generated.h
libgkd_dbus_la_SOURCES = \
$(BUILT_SOURCES) \
diff --git a/daemon/dbus/gkd-secret-service.c b/daemon/dbus/gkd-secret-service.c
index 69a42b4b..378180b5 100644
--- a/daemon/dbus/gkd-secret-service.c
+++ b/daemon/dbus/gkd-secret-service.c
@@ -37,11 +37,16 @@
#include "gkd-internal-generated.h"
#include "gkd-secrets-generated.h"
+#include "gkd-portal-generated.h"
+#include "gkd-portal-request-generated.h"
#include "egg/egg-error.h"
#include "egg/egg-unix-credentials.h"
#include <gck/gck.h>
+#include <gio/gunixfdlist.h>
+#include <gio/gunixoutputstream.h>
+#include <gcrypt.h>
#include "pkcs11/pkcs11i.h"
@@ -126,6 +131,7 @@ struct _GkdSecretService {
GDBusConnection *connection;
GkdExportedService *skeleton;
GkdExportedInternal *internal_skeleton;
+ GkdExportedPortal *portal_skeleton;
guint name_owner_id;
guint filter_id;
@@ -911,6 +917,177 @@ service_method_unlock_with_master_password (GkdExportedInternal *skeleton,
return TRUE;
}
+static gboolean
+service_method_close (GkdExportedPortalRequest *skeleton,
+ GDBusMethodInvocation *invocation,
+ GkdSecretService *self)
+{
+ g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (skeleton));
+ return TRUE;
+}
+
+#define DEFAULT_KEY_SIZE 64
+
+static gboolean
+create_application_attributes (const char *app_id,
+ GckBuilder *builder)
+{
+ GVariantBuilder attributes =
+ G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
+
+ g_variant_builder_add (&attributes, "sv",
+ "app_id", g_variant_new_string (app_id));
+
+ return gkd_secret_property_parse_fields (g_variant_builder_end (&attributes),
+ builder);
+}
+
+static gboolean
+service_method_retrieve_secret (GkdExportedPortal *skeleton,
+ GDBusMethodInvocation *invocation,
+ GUnixFDList *fd_list,
+ const gchar *arg_handle,
+ const gchar *arg_app_id,
+ GVariant *arg_fd,
+ GVariant *arg_options,
+ GkdSecretService *self)
+{
+ GckBuilder builder = GCK_BUILDER_INIT;
+ GckObject *search;
+ int idx, fd;
+ gpointer data = NULL;
+ gsize n_data = 0;
+ GError *error = NULL;
+ GkdExportedPortalRequest *request_skeleton;
+ guint8 *value = NULL;
+ gsize n_value = 0;
+ GOutputStream *stream;
+
+ request_skeleton = gkd_exported_portal_request_skeleton_new ();
+ if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (request_skeleton),
+ g_dbus_method_invocation_get_connection (invocation),
+ arg_handle, &error)) {
+ g_warning ("error exporting request: %s\n", error->message);
+ g_clear_error (&error);
+ } else {
+ g_signal_connect (request_skeleton, "handle-close",
+ G_CALLBACK (service_method_close), self);
+ }
+
+ g_variant_get (arg_fd, "h", &idx);
+ fd = g_unix_fd_list_get (fd_list, idx, NULL);
+
+ if (!create_application_attributes (arg_app_id, &builder)) {
+ gck_builder_clear (&builder);
+ g_dbus_method_invocation_return_error_literal (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Invalid data in attributes argument");
+ return TRUE;
+ }
+
+ /* Find items matching the collection and fields */
+ gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_SEARCH);
+ gck_builder_add_boolean (&builder, CKA_TOKEN, FALSE);
+ gck_builder_add_string (&builder, CKA_G_COLLECTION, "login");
+
+ /* Create the search object */
+ search = gck_session_create_object (self->internal_session,
+ gck_builder_end (&builder),
+ NULL, &error);
+ if (error != NULL) {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Couldn't search for items: %s",
+ error->message);
+ g_clear_error (&error);
+ return TRUE;
+ }
+
+ /* Get the matched item handles, and delete the search object */
+ data = gck_object_get_data (search, CKA_G_MATCHED, NULL, &n_data, &error);
+ gck_object_destroy (search, NULL, NULL);
+ g_object_unref (search);
+
+ if (error != NULL) {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Couldn't retrieve matched items: %s",
+ error->message);
+ g_clear_error (&error);
+ return TRUE;
+ }
+
+ if (n_data > 0) {
+ /* Return the first matching item if any */
+ GList *items;
+
+ /* Build a list of object handles */
+ items = gck_objects_from_handle_array (self->internal_session, data, n_data / sizeof
(CK_OBJECT_HANDLE));
+ g_clear_pointer (&data, g_free);
+
+ value = gck_object_get_data (GCK_OBJECT (items->data),
+ CKA_VALUE,
+ NULL,
+ &n_value,
+ &error);
+ if (value == NULL) {
+ g_dbus_method_invocation_take_error (invocation, error);
+ return TRUE;
+ }
+ } else {
+ /* Otherwise create a new random key */
+ GckObject *item = NULL;
+
+ g_clear_pointer (&data, g_free);
+
+ value = g_new0 (guint8, DEFAULT_KEY_SIZE);
+ n_value = DEFAULT_KEY_SIZE;
+
+ gcry_randomize (value, n_value, GCRY_STRONG_RANDOM);
+
+ /* Create a new item */
+ if (!create_application_attributes (arg_app_id, &builder)) {
+ gck_builder_clear (&builder);
+ g_dbus_method_invocation_return_error_literal (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Invalid data in attributes argument");
+ return TRUE;
+ }
+
+ gck_builder_add_string (&builder, CKA_G_COLLECTION, "login");
+ gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
+ gck_builder_add_data (&builder, CKA_VALUE, value, n_value);
+ item = gck_session_create_object (self->internal_session, gck_builder_end (&builder), NULL,
&error);
+ if (item == NULL) {
+ g_dbus_method_invocation_take_error (invocation, error);
+ return TRUE;
+ }
+ g_object_unref (item);
+ }
+
+ stream = g_unix_output_stream_new (fd, FALSE);
+ if (!g_output_stream_write_all (stream, value, n_value, NULL, NULL, &error)) {
+ g_free (value);
+ g_object_unref (stream);
+ g_dbus_method_invocation_take_error (invocation, error);
+ return TRUE;
+ }
+ g_free (value);
+ g_object_unref (stream);
+
+ gkd_exported_portal_complete_retrieve_secret (skeleton,
+ invocation,
+ NULL,
+ 0,
+ NULL);
+
+ return TRUE;
+}
+
static void
service_name_owner_changed (GDBusConnection *connection,
const gchar *sender_name,
@@ -1034,6 +1211,19 @@ gkd_secret_service_constructor (GType type,
g_signal_connect (self->internal_skeleton, "handle-unlock-with-master-password",
G_CALLBACK (service_method_unlock_with_master_password), self);
+ self->portal_skeleton = gkd_exported_portal_skeleton_new ();
+ g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self->portal_skeleton),
+ self->connection,
+ SECRET_SERVICE_PATH, &error);
+
+ if (error != NULL) {
+ g_warning ("could not register portal interface service on session bus: %s", error->message);
+ g_clear_error (&error);
+ }
+
+ g_signal_connect (self->portal_skeleton, "handle-retrieve-secret",
+ G_CALLBACK (service_method_retrieve_secret), self);
+
self->name_owner_id = g_dbus_connection_signal_subscribe (self->connection,
NULL,
"org.freedesktop.DBus",
diff --git a/daemon/dbus/org.freedesktop.impl.portal.Request.xml
b/daemon/dbus/org.freedesktop.impl.portal.Request.xml
new file mode 100644
index 00000000..4402c40a
--- /dev/null
+++ b/daemon/dbus/org.freedesktop.impl.portal.Request.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0"?>
+<!--
+ Copyright (C) 2016 Red Hat, Inc.
+
+ This library 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 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+ Author: Alexander Larsson <alexl redhat com>
+ Matthias Clasen <mclasen redhat com>
+-->
+
+<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
+ <!--
+ org.freedesktop.impl.portal.Request:
+ @short_description: Shared request interface
+
+ The Request interface is shared by all portal backend interfaces.
+ When a backend method is called, the backend exports a Request object
+ on the object path that was sent with the method call. The Request
+ will stay alive for the duration of the user interaction related to
+ the method call.
+
+ The portal can abort the interaction calling
+ org.freedesktop.impl.portal.Request.Close() on the Request object.
+ -->
+ <interface name="org.freedesktop.impl.portal.Request">
+
+ <!--
+ Close:
+
+ Ends the user interaction to which this object refers.
+ Dialogs and other UIs related to the request should be closed.
+ -->
+ <method name="Close">
+ </method>
+ </interface>
+</node>
diff --git a/daemon/dbus/org.freedesktop.impl.portal.Secret.xml
b/daemon/dbus/org.freedesktop.impl.portal.Secret.xml
new file mode 100644
index 00000000..c33d85e2
--- /dev/null
+++ b/daemon/dbus/org.freedesktop.impl.portal.Secret.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+<!--
+ Copyright (C) 2019 Red Hat, Inc.
+
+ This library 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 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+ Author: Daiki Ueno <dueno redhat com>
+-->
+
+<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
+ <!--
+ org.freedesktop.impl.portal.Secret:
+ @short_description: Secret portal backend interface
+
+ The Secret portal allows sandboxed applications to retrieve a
+ per-application master secret.
+ -->
+ <interface name="org.freedesktop.impl.portal.Secret">
+
+ <!--
+ RetrieveSecret:
+ @handle: Object path for the #org.freedesktop.impl.portal.Request object representing this call
+ @app_id: App id of the application
+ @fd: File descriptor for reading the secret
+ @options: Vardict with optional further information
+ @results: Vardict with the results of the call
+
+ Retrieves a master secret for a sandboxed application.
+
+ Supported keys in the @options vardict include:
+ <variablelist>
+ <varlistentry>
+ <term>token s</term>
+ <listitem><para>
+ An opaque string associated with the retrieve secret.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+ -->
+ <method name="RetrieveSecret">
+ <annotation name="org.gtk.GDBus.C.Name" value="retrieve_secret"/>
+ <annotation name="org.gtk.GDBus.C.UnixFD" value="true"/>
+ <arg type="o" name="handle" direction="in"/>
+ <arg type="s" name="app_id" direction="in"/>
+ <arg type="h" name="fd" direction="in"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.In3" value="QVariantMap"/>
+ <arg type="a{sv}" name="options" direction="in"/>
+ <arg type="u" name="response" direction="out"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap"/>
+ <arg type="a{sv}" name="results" direction="out"/>
+ </method>
+ <property name="version" type="u" access="read"/>
+ </interface>
+</node>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]