summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaiki Ueno <ueno@gnu.org>2019-10-08 08:20:05 +0000
committerDaiki Ueno <ueno@gnu.org>2019-10-08 08:20:05 +0000
commit4b6d735b82f42dac36c16e63624853162abac33a (patch)
tree077aedec11f891e8fe51185be5d9426e2c48562d
parent616a967e60615337ccd0b3fdcb9dcb8892941126 (diff)
parenta6317352e8357b44d36e53cba80dedfd69a30630 (diff)
downloadlibsecret-4b6d735b82f42dac36c16e63624853162abac33a.tar.gz
Merge branch 'wip/dueno/backend' into 'master'
secret-backend: New interface to represent password storage backend See merge request GNOME/libsecret!34
-rw-r--r--docs/reference/libsecret/libsecret-sections.txt14
-rw-r--r--libsecret/Makefile.am2
-rw-r--r--libsecret/Secret-1.metadata6
-rw-r--r--libsecret/meson.build4
-rw-r--r--libsecret/secret-backend.c294
-rw-r--r--libsecret/secret-backend.h113
-rw-r--r--libsecret/secret-password.c403
-rw-r--r--libsecret/secret-service.c235
8 files changed, 1004 insertions, 67 deletions
diff --git a/docs/reference/libsecret/libsecret-sections.txt b/docs/reference/libsecret/libsecret-sections.txt
index f811b9d..1b225fe 100644
--- a/docs/reference/libsecret/libsecret-sections.txt
+++ b/docs/reference/libsecret/libsecret-sections.txt
@@ -367,6 +367,20 @@ secret_attributes_buildv
</SECTION>
<SECTION>
+<FILE>secret-backend</FILE>
+SECRET_BACKEND_EXTENSION_POINT_NAME
+SECRET_TYPE_BACKEND
+SECRET_TYPE_BACKEND_FLAGS
+SECRET_TYPE_SCHEMA_TYPE
+SecretBackend
+SecretBackendFlags
+SecretBackendInterface
+secret_backend_flags_get_type
+secret_backend_get
+secret_backend_get_finish
+</SECTION>
+
+<SECTION>
<FILE>secret-version</FILE>
SECRET_CHECK_VERSION
SECRET_MAJOR_VERSION
diff --git a/libsecret/Makefile.am b/libsecret/Makefile.am
index 0e661b8..0e34ea3 100644
--- a/libsecret/Makefile.am
+++ b/libsecret/Makefile.am
@@ -7,6 +7,7 @@ incdir = $(includedir)/libsecret-@SECRET_MAJOR@/libsecret
libsecret_HEADS = \
libsecret/secret.h \
libsecret/secret-attributes.h \
+ libsecret/secret-backend.h \
libsecret/secret-collection.h \
libsecret/secret-item.h \
libsecret/secret-password.h \
@@ -38,6 +39,7 @@ libsecret_BUILT = \
libsecret_PUBLIC = \
libsecret/secret-attributes.h libsecret/secret-attributes.c \
+ libsecret/secret-backend.h libsecret/secret-backend.c \
libsecret/secret-collection.h libsecret/secret-collection.c \
libsecret/secret-item.h libsecret/secret-item.c \
libsecret/secret-methods.c \
diff --git a/libsecret/Secret-1.metadata b/libsecret/Secret-1.metadata
index bc9e364..8288950 100644
--- a/libsecret/Secret-1.metadata
+++ b/libsecret/Secret-1.metadata
@@ -66,3 +66,9 @@ Service
.prompt_at_dbus_path_sync skip=false nullable=true
.prompt_at_dbus_path skip=false
.prompt_at_dbus_path_finish skip=false nullable=true
+
+Backend
+ .search_finish skip=false type="GLib.List<Secret.Item>"
+ .*#virtual_method.schema nullable
+ .*#virtual_method.attributes type="GLib.HashTable<string,string>"
+ .*#virtual_method.collection nullable
diff --git a/libsecret/meson.build b/libsecret/meson.build
index f7077cd..0421ac9 100644
--- a/libsecret/meson.build
+++ b/libsecret/meson.build
@@ -2,6 +2,7 @@ installed_headers_subdir = 'libsecret-@0@'.format(api_version_major) / 'libsecre
libsecret_sources = [
'secret-attributes.c',
+ 'secret-backend.c',
'secret-collection.c',
'secret-item.c',
'secret-methods.c',
@@ -20,6 +21,7 @@ libsecret_sources = [
libsecret_headers = [
'secret.h',
'secret-attributes.h',
+ 'secret-backend.h',
'secret-collection.h',
'secret-item.h',
'secret-password.h',
@@ -96,6 +98,8 @@ libsecret_dep = declare_dependency(
libsecret_gir_sources = [
'secret-attributes.c',
'secret-attributes.h',
+ 'secret-backend.c',
+ 'secret-backend.h',
'secret-collection.c',
'secret-collection.h',
'secret-item.c',
diff --git a/libsecret/secret-backend.c b/libsecret/secret-backend.c
new file mode 100644
index 0000000..a63b75c
--- /dev/null
+++ b/libsecret/secret-backend.c
@@ -0,0 +1,294 @@
+/* libsecret - GLib wrapper for Secret Service
+ *
+ * Copyright 2019 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 licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Author: Daiki Ueno
+ */
+
+#include "config.h"
+
+#include "secret-backend.h"
+#include "secret-private.h"
+
+#include "libsecret/secret-enum-types.h"
+
+/**
+ * SECTION:secret-backend
+ * @title: SecretBackend
+ * @short_description: A backend implementation of password storage
+ *
+ * #SecretBackend represents a backend implementation of password
+ * storage.
+ *
+ * Stability: Stable
+ */
+
+/**
+ * SecretBackend:
+ *
+ * An object representing a backend implementation of password storage.
+ *
+ * Since: 0.19.0
+ */
+
+/**
+ * SecretBackendInterface:
+ * @parent_iface: the parent interface
+ * @ensure_for_flags: implementation of reinitialization step in constructor, optional
+ * @ensure_for_flags_finish: implementation of reinitialization step in constructor, optional
+ * @store: implementation of secret_password_store(), required
+ * @store_finish: implementation of secret_password_store_finish(), required
+ * @lookup: implementation of secret_password_lookup(), required
+ * @lookup_finish: implementation of secret_password_lookup_finish(), required
+ * @clear: implementation of secret_password_clear(), required
+ * @clear_finish: implementation of secret_password_clear_finish(), required
+ * @search: implementation of secret_password_search(), required
+ * @search_finish: implementation of secret_password_search_finish(), required
+ *
+ * The interface for #SecretBackend.
+ *
+ * Since: 0.19.0
+ */
+
+/**
+ * SecretBackendFlags:
+ * @SECRET_BACKEND_NONE: no flags for initializing the #SecretBackend
+ * @SECRET_BACKEND_OPEN_SESSION: establish a session for transfer of secrets
+ * while initializing the #SecretBackend
+ * @SECRET_BACKEND_LOAD_COLLECTIONS: load collections while initializing the
+ * #SecretBackend
+ *
+ * Flags which determine which parts of the #SecretBackend are initialized.
+ *
+ * Since: 0.19.0
+ */
+
+G_DEFINE_INTERFACE_WITH_CODE (SecretBackend, secret_backend, G_TYPE_OBJECT,
+ g_type_interface_add_prerequisite(g_define_type_id, G_TYPE_ASYNC_INITABLE);
+);
+
+static void
+secret_backend_default_init (SecretBackendInterface *iface)
+{
+ /**
+ * SecretBackend:flags:
+ *
+ * A set of flags describing which parts of the secret backend have
+ * been initialized.
+ *
+ * Since: 0.19.0
+ */
+ g_object_interface_install_property (iface,
+ g_param_spec_flags ("flags", "Flags", "Service flags",
+ secret_service_flags_get_type (), SECRET_SERVICE_NONE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+}
+
+void
+_secret_backend_ensure_extension_point (void)
+{
+ GIOExtensionPoint *ep;
+ static gboolean registered = FALSE;
+
+ if (registered)
+ return;
+
+ ep = g_io_extension_point_register (SECRET_BACKEND_EXTENSION_POINT_NAME);
+ g_io_extension_point_set_required_type (ep, SECRET_TYPE_BACKEND);
+
+ registered = TRUE;
+}
+
+G_LOCK_DEFINE (backend_instance);
+static gpointer backend_instance = NULL;
+
+static SecretBackend *
+backend_get_instance (void)
+{
+ SecretBackend *instance = NULL;
+
+ G_LOCK (backend_instance);
+ if (backend_instance != NULL)
+ instance = g_object_ref (backend_instance);
+ G_UNLOCK (backend_instance);
+
+ return instance;
+}
+
+void
+_secret_backend_uncache_instance (void)
+{
+ SecretBackend *instance = NULL;
+
+ G_LOCK (backend_instance);
+ instance = backend_instance;
+ backend_instance = NULL;
+ G_UNLOCK (backend_instance);
+
+ if (instance != NULL)
+ g_object_unref (instance);
+}
+
+static GType
+backend_get_impl_type (void)
+{
+ const gchar *envvar;
+ const gchar *extension_name;
+ GIOExtension *e;
+ GIOExtensionPoint *ep;
+
+ envvar = g_getenv ("SECRET_BACKEND");
+ if (envvar == NULL || *envvar == '\0')
+ extension_name = "service";
+ else
+ extension_name = envvar;
+
+ g_type_ensure (secret_service_get_type ());
+
+ ep = g_io_extension_point_lookup (SECRET_BACKEND_EXTENSION_POINT_NAME);
+ e = g_io_extension_point_get_extension_by_name (ep, extension_name);
+ if (e == NULL) {
+ g_warning ("Backend extension \"%s\" from SECRET_BACKEND_EXTENSION_POINT_NAME environment variable not found.", extension_name);
+ return G_TYPE_NONE;
+ }
+
+ return g_io_extension_get_type (e);
+}
+
+static void
+on_ensure_for_flags (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ SecretBackendInterface *iface;
+ SecretBackend *self = SECRET_BACKEND (source_object);
+ GTask *task = G_TASK (user_data);
+ GError *error = NULL;
+
+ iface = SECRET_BACKEND_GET_IFACE (self);
+ if (iface->ensure_for_flags_finish) {
+ if (!iface->ensure_for_flags_finish (self, result, &error)) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+ }
+
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+/**
+ * secret_backend_get:
+ * @flags: flags for which service functionality to ensure is initialized
+ * @cancellable: optional cancellation object
+ * @callback: called when the operation completes
+ * @user_data: data to be passed to the callback
+ *
+ * Get a #SecretBackend instance. If such a backend already exists,
+ * then the same backend is returned.
+ *
+ * If @flags contains any flags of which parts of the secret backend to
+ * ensure are initialized, then those will be initialized before completing.
+ *
+ * This method will return immediately and complete asynchronously.
+ *
+ * Since: 0.19.0
+ */
+void
+secret_backend_get (SecretBackendFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ SecretBackend *backend = NULL;
+ SecretBackendInterface *iface;
+ GTask *task;
+
+ backend = backend_get_instance ();
+
+ /* Create a whole new backend */
+ if (backend == NULL) {
+ GType impl_type = backend_get_impl_type ();
+ g_return_if_fail (g_type_is_a (impl_type, G_TYPE_ASYNC_INITABLE));
+ g_async_initable_new_async (impl_type,
+ G_PRIORITY_DEFAULT,
+ cancellable, callback, user_data,
+ "flags", flags,
+ NULL);
+
+ /* Just have to ensure that the backend matches flags */
+ } else {
+ task = g_task_new (backend, cancellable, callback, user_data);
+ iface = SECRET_BACKEND_GET_IFACE (backend);
+ if (iface->ensure_for_flags) {
+ g_task_set_source_tag (task, secret_backend_get);
+ iface->ensure_for_flags (backend, flags, cancellable,
+ on_ensure_for_flags, task);
+ } else {
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ }
+ g_object_unref (backend);
+ }
+}
+
+/**
+ * secret_backend_get_finish:
+ * @result: the asynchronous result passed to the callback
+ * @error: location to place an error on failure
+ *
+ * Complete an asynchronous operation to get a #SecretBackend.
+ *
+ * Returns: (transfer full): a new reference to a #SecretBackend proxy, which
+ * should be released with g_object_unref().
+ *
+ * Since: 0.19.0
+ */
+SecretBackend *
+secret_backend_get_finish (GAsyncResult *result,
+ GError **error)
+{
+ GTask *task;
+ GObject *backend = NULL;
+ GObject *source_object;
+
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ task = G_TASK (result);
+ source_object = g_task_get_source_object (task);
+
+ g_return_val_if_fail (g_task_is_valid (result, source_object), NULL);
+
+ /* Just ensuring that the backend matches flags */
+ if (g_task_get_source_tag (task) == secret_backend_get) {
+ if (g_task_had_error (task)) {
+ g_task_propagate_pointer (task, error);
+ } else {
+ backend = g_object_ref (source_object);
+ }
+
+ /* Creating a whole new backend */
+ } else {
+ backend = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error);
+ if (backend) {
+ G_LOCK (backend_instance);
+ if (backend_instance == NULL)
+ backend_instance = backend;
+ G_UNLOCK (backend_instance);
+ }
+ }
+
+ if (backend == NULL)
+ return NULL;
+
+ return SECRET_BACKEND (backend);
+}
diff --git a/libsecret/secret-backend.h b/libsecret/secret-backend.h
new file mode 100644
index 0000000..3dadffa
--- /dev/null
+++ b/libsecret/secret-backend.h
@@ -0,0 +1,113 @@
+/* libsecret - GLib wrapper for Secret Service
+ *
+ * Copyright 2019 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 licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Author: Daiki Ueno
+ */
+
+#if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION)
+#error "Only <libsecret/secret.h> can be included directly."
+#endif
+
+#ifndef __SECRET_BACKEND_H__
+#define __SECRET_BACKEND_H__
+
+#include <glib-object.h>
+#include "secret-schema.h"
+#include "secret-service.h"
+#include "secret-value.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+ SECRET_BACKEND_NONE = SECRET_SERVICE_NONE,
+ SECRET_BACKEND_OPEN_SESSION = SECRET_SERVICE_OPEN_SESSION,
+ SECRET_BACKEND_LOAD_COLLECTIONS = SECRET_SERVICE_LOAD_COLLECTIONS,
+} SecretBackendFlags;
+
+#define SECRET_TYPE_BACKEND secret_backend_get_type ()
+G_DECLARE_INTERFACE (SecretBackend, secret_backend, SECRET, BACKEND, GObject)
+
+struct _SecretBackendInterface
+{
+ GTypeInterface parent_iface;
+
+ void (*ensure_for_flags) (SecretBackend *self,
+ SecretBackendFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gboolean (*ensure_for_flags_finish) (SecretBackend *self,
+ GAsyncResult *result,
+ GError **error);
+
+ void (*store) (SecretBackend *self,
+ const SecretSchema *schema,
+ GHashTable *attributes,
+ const gchar *collection,
+ const gchar *label,
+ SecretValue *value,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gboolean (*store_finish) (SecretBackend *self,
+ GAsyncResult *result,
+ GError **error);
+
+ void (*lookup) (SecretBackend *self,
+ const SecretSchema *schema,
+ GHashTable *attributes,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ SecretValue *(*lookup_finish) (SecretBackend *self,
+ GAsyncResult *result,
+ GError **error);
+
+ void (*clear) (SecretBackend *self,
+ const SecretSchema *schema,
+ GHashTable *attributes,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gboolean (*clear_finish) (SecretBackend *self,
+ GAsyncResult *result,
+ GError **error);
+
+ void (*search) (SecretBackend *self,
+ const SecretSchema *schema,
+ GHashTable *attributes,
+ SecretSearchFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ GList * (*search_finish) (SecretBackend *self,
+ GAsyncResult *result,
+ GError **error);
+};
+
+#define SECRET_BACKEND_EXTENSION_POINT_NAME "secret-backend"
+
+void _secret_backend_ensure_extension_point
+ (void);
+void _secret_backend_uncache_instance
+ (void);
+
+void secret_backend_get (SecretBackendFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+SecretBackend *secret_backend_get_finish (GAsyncResult *result,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __SECRET_BACKEND_H__ */
diff --git a/libsecret/secret-password.c b/libsecret/secret-password.c
index 632ed2d..491e211 100644
--- a/libsecret/secret-password.c
+++ b/libsecret/secret-password.c
@@ -18,6 +18,7 @@
#include "secret-password.h"
#include "secret-private.h"
#include "secret-retrievable.h"
+#include "secret-backend.h"
#include "secret-value.h"
#include <egg/egg-secure-memory.h>
@@ -102,15 +103,86 @@ secret_password_store (const SecretSchema *schema,
g_hash_table_unref (attributes);
}
+typedef struct {
+ const SecretSchema *schema;
+ GHashTable *attributes;
+ gchar *collection;
+ gchar *label;
+ SecretValue *value;
+} StoreClosure;
+
+static void
+store_closure_free (gpointer data)
+{
+ StoreClosure *store = data;
+ _secret_schema_unref_if_nonstatic (store->schema);
+ g_hash_table_unref (store->attributes);
+ g_free (store->collection);
+ g_free (store->label);
+ secret_value_unref (store->value);
+ g_slice_free (StoreClosure, store);
+}
+
+static void
+on_store (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GTask *task = G_TASK (user_data);
+ SecretBackend *backend = SECRET_BACKEND (source);
+ SecretBackendInterface *iface;
+ GError *error = NULL;
+
+ iface = SECRET_BACKEND_GET_IFACE (backend);
+ g_return_if_fail (iface->store_finish != NULL);
+
+ if (!iface->store_finish (backend, result, &error)) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static void
+on_store_backend (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GTask *task = G_TASK (user_data);
+ StoreClosure *store = g_task_get_task_data (task);
+ SecretBackend *backend;
+ SecretBackendInterface *iface;
+ GError *error = NULL;
+
+ backend = secret_backend_get_finish (result, &error);
+ if (backend == NULL) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ iface = SECRET_BACKEND_GET_IFACE (backend);
+ g_return_if_fail (iface->store != NULL);
+
+ iface->store (backend, store->schema, store->attributes,
+ store->collection, store->label, store->value,
+ g_task_get_cancellable (task),
+ on_store,
+ task);
+}
+
/**
* secret_password_storev: (rename-to secret_password_store)
* @schema: (nullable): the schema for attributes
- * @attributes: (element-type utf8 utf8): the attribute keys and values
+ * @attributes: (element-type utf8 utf8) (transfer full): the attribute keys and values
* @collection: (allow-none): a collection alias, or D-Bus object path of the collection where to store the secret
* @label: label for the secret
* @password: the null-terminated password to store
* @cancellable: optional cancellation object
- * @callback: called when the operation completes
+ * @callback: (scope async): called when the operation completes
* @user_data: data to be passed to the callback
*
* Store a password in the secret service.
@@ -136,7 +208,8 @@ secret_password_storev (const SecretSchema *schema,
GAsyncReadyCallback callback,
gpointer user_data)
{
- SecretValue *value;
+ StoreClosure *store;
+ GTask *task;
g_return_if_fail (label != NULL);
g_return_if_fail (password != NULL);
@@ -147,12 +220,18 @@ secret_password_storev (const SecretSchema *schema,
if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE))
return;
- value = secret_value_new (password, -1, "text/plain");
-
- secret_service_store (NULL, schema, attributes, collection,
- label, value, cancellable, callback, user_data);
-
- secret_value_unref (value);
+ task = g_task_new (NULL, cancellable, callback, user_data);
+ store = g_slice_new0 (StoreClosure);
+ store->schema = _secret_schema_ref_if_nonstatic (schema);
+ store->attributes = g_hash_table_ref (attributes);
+ store->collection = g_strdup (collection);
+ store->label = g_strdup (label);
+ store->value = secret_value_new (password, -1, "text/plain");
+ g_task_set_task_data (task, store, store_closure_free);
+
+ secret_backend_get (SECRET_BACKEND_OPEN_SESSION,
+ cancellable,
+ on_store_backend, task);
}
/**
@@ -210,12 +289,12 @@ secret_password_store_binary (const SecretSchema *schema,
/**
* secret_password_storev_binary: (rename-to secret_password_store_binary)
* @schema: (nullable): the schema for attributes
- * @attributes: (element-type utf8 utf8): the attribute keys and values
+ * @attributes: (element-type utf8 utf8) (transfer full): the attribute keys and values
* @collection: (allow-none): a collection alias, or D-Bus object path of the collection where to store the secret
* @label: label for the secret
* @value: a #SecretValue
* @cancellable: optional cancellation object
- * @callback: called when the operation completes
+ * @callback: (scope async): called when the operation completes
* @user_data: data to be passed to the callback
*
* Store a password in the secret service.
@@ -237,6 +316,9 @@ secret_password_storev_binary (const SecretSchema *schema,
GAsyncReadyCallback callback,
gpointer user_data)
{
+ StoreClosure *store;
+ GTask *task;
+
g_return_if_fail (label != NULL);
g_return_if_fail (value != NULL);
g_return_if_fail (attributes != NULL);
@@ -246,8 +328,18 @@ secret_password_storev_binary (const SecretSchema *schema,
if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE))
return;
- secret_service_store (NULL, schema, attributes, collection,
- label, value, cancellable, callback, user_data);
+ task = g_task_new (NULL, cancellable, callback, user_data);
+ store = g_slice_new0 (StoreClosure);
+ store->schema = _secret_schema_ref_if_nonstatic (schema);
+ store->attributes = g_hash_table_ref (attributes);
+ store->collection = g_strdup (collection);
+ store->label = g_strdup (label);
+ store->value = secret_value_ref (value);
+ g_task_set_task_data (task, store, store_closure_free);
+
+ secret_backend_get (SECRET_BACKEND_OPEN_SESSION,
+ cancellable,
+ on_store_backend, task);
}
/**
@@ -264,7 +356,9 @@ secret_password_store_finish (GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
- return secret_service_store_finish (NULL, result, error);
+ g_return_val_if_fail (g_task_is_valid (result, NULL), FALSE);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
}
/**
@@ -556,12 +650,81 @@ secret_password_lookup (const SecretSchema *schema,
g_hash_table_unref (attributes);
}
+typedef struct {
+ const SecretSchema *schema;
+ GHashTable *attributes;
+} LookupClosure;
+
+static void
+lookup_closure_free (gpointer data)
+{
+ LookupClosure *closure = data;
+ _secret_schema_unref_if_nonstatic (closure->schema);
+ g_hash_table_unref (closure->attributes);
+ g_slice_free (LookupClosure, closure);
+}
+
+static void
+on_lookup (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GTask *task = G_TASK (user_data);
+ SecretBackend *backend = SECRET_BACKEND (source);
+ SecretBackendInterface *iface;
+ SecretValue *value;
+ GError *error = NULL;
+
+ iface = SECRET_BACKEND_GET_IFACE (backend);
+ g_return_if_fail (iface->store_finish != NULL);
+
+ value = iface->lookup_finish (backend, result, &error);
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ if (value)
+ g_task_return_pointer (task, value, secret_value_unref);
+ else
+ g_task_return_pointer (task, NULL, NULL);
+ g_object_unref (task);
+}
+
+static void
+on_lookup_backend (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GTask *task = G_TASK (user_data);
+ LookupClosure *lookup = g_task_get_task_data (task);
+ SecretBackend *backend;
+ SecretBackendInterface *iface;
+ GError *error = NULL;
+
+ backend = secret_backend_get_finish (result, &error);
+ if (backend == NULL) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ iface = SECRET_BACKEND_GET_IFACE (backend);
+ g_return_if_fail (iface->store != NULL);
+
+ iface->lookup (backend, lookup->schema, lookup->attributes,
+ g_task_get_cancellable (task),
+ on_lookup,
+ task);
+}
+
/**
* secret_password_lookupv: (rename-to secret_password_lookup)
* @schema: (nullable): the schema for attributes
- * @attributes: (element-type utf8 utf8): the attribute keys and values
+ * @attributes: (element-type utf8 utf8) (transfer full): the attribute keys and values
* @cancellable: optional cancellation object
- * @callback: called when the operation completes
+ * @callback: (scope async): called when the operation completes
* @user_data: data to be passed to the callback
*
* Lookup a password in the secret service.
@@ -579,6 +742,9 @@ secret_password_lookupv (const SecretSchema *schema,
GAsyncReadyCallback callback,
gpointer user_data)
{
+ LookupClosure *lookup;
+ GTask *task;
+
g_return_if_fail (attributes != NULL);
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
@@ -586,8 +752,15 @@ secret_password_lookupv (const SecretSchema *schema,
if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
return;
- secret_service_lookup (NULL, schema, attributes,
- cancellable, callback, user_data);
+ task = g_task_new (NULL, cancellable, callback, user_data);
+ lookup = g_slice_new0 (LookupClosure);
+ lookup->schema = _secret_schema_ref_if_nonstatic (schema);
+ lookup->attributes = g_hash_table_ref (attributes);
+ g_task_set_task_data (task, lookup, lookup_closure_free);
+
+ secret_backend_get (SECRET_BACKEND_OPEN_SESSION,
+ cancellable,
+ on_lookup_backend, task);
}
/**
@@ -607,8 +780,9 @@ secret_password_lookup_nonpageable_finish (GAsyncResult *result,
SecretValue *value;
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
- value = secret_service_lookup_finish (NULL, result, error);
+ value = g_task_propagate_pointer (G_TASK (result), error);
if (value == NULL)
return NULL;
@@ -632,8 +806,9 @@ secret_password_lookup_binary_finish (GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
- return secret_service_lookup_finish (NULL, result, error);
+ return g_task_propagate_pointer (G_TASK (result), error);
}
/**
@@ -653,8 +828,9 @@ secret_password_lookup_finish (GAsyncResult *result,
SecretValue *value;
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
- value = secret_service_lookup_finish (NULL, result, error);
+ value = g_task_propagate_pointer (G_TASK (result), error);
if (value == NULL)
return NULL;
@@ -1018,13 +1194,79 @@ secret_password_clear (const SecretSchema *schema,
g_hash_table_unref (attributes);
}
+typedef struct {
+ const SecretSchema *schema;
+ GHashTable *attributes;
+} ClearClosure;
+
+static void
+clear_closure_free (gpointer data)
+{
+ ClearClosure *closure = data;
+ _secret_schema_unref_if_nonstatic (closure->schema);
+ g_hash_table_unref (closure->attributes);
+ g_slice_free (ClearClosure, closure);
+}
+
+static void
+on_clear (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GTask *task = G_TASK (user_data);
+ SecretBackend *backend = SECRET_BACKEND (source);
+ SecretBackendInterface *iface;
+ GError *error = NULL;
+
+ iface = SECRET_BACKEND_GET_IFACE (backend);
+ g_return_if_fail (iface->clear_finish != NULL);
+
+ if (!iface->clear_finish (backend, result, &error)) {
+ if (error)
+ g_task_return_error (task, error);
+ else
+ g_task_return_boolean (task, FALSE);
+ g_object_unref (task);
+ return;
+ }
+
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static void
+on_clear_backend (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GTask *task = G_TASK (user_data);
+ ClearClosure *clear = g_task_get_task_data (task);
+ SecretBackend *backend;
+ SecretBackendInterface *iface;
+ GError *error = NULL;
+
+ backend = secret_backend_get_finish (result, &error);
+ if (backend == NULL) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ iface = SECRET_BACKEND_GET_IFACE (backend);
+ g_return_if_fail (iface->clear != NULL);
+
+ iface->clear (backend, clear->schema, clear->attributes,
+ g_task_get_cancellable (task),
+ on_clear,
+ task);
+}
/**
* secret_password_clearv: (rename-to secret_password_clear)
* @schema: (nullable): the schema for the attributes
- * @attributes: (element-type utf8 utf8): the attribute keys and values
+ * @attributes: (element-type utf8 utf8) (transfer full): the attribute keys and values
* @cancellable: optional cancellation object
- * @callback: called when the operation completes
+ * @callback: (scope async): called when the operation completes
* @user_data: data to be passed to the callback
*
* Remove unlocked matching passwords from the secret service.
@@ -1042,6 +1284,9 @@ secret_password_clearv (const SecretSchema *schema,
GAsyncReadyCallback callback,
gpointer user_data)
{
+ ClearClosure *clear;
+ GTask *task;
+
g_return_if_fail (attributes != NULL);
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
@@ -1049,8 +1294,15 @@ secret_password_clearv (const SecretSchema *schema,
if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
return;
- secret_service_clear (NULL, schema, attributes,
- cancellable, callback, user_data);
+ task = g_task_new (NULL, cancellable, callback, user_data);
+ clear = g_slice_new0 (ClearClosure);
+ clear->schema = _secret_schema_ref_if_nonstatic (schema);
+ clear->attributes = g_hash_table_ref (attributes);
+ g_task_set_task_data (task, clear, clear_closure_free);
+
+ secret_backend_get (SECRET_SERVICE_NONE,
+ cancellable,
+ on_clear_backend, task);
}
/**
@@ -1068,7 +1320,9 @@ secret_password_clear_finish (GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
- return secret_service_clear_finish (NULL, result, error);
+ g_return_val_if_fail (g_task_is_valid (result, NULL), FALSE);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
}
/**
@@ -1221,13 +1475,88 @@ secret_password_search (const SecretSchema *schema,
g_hash_table_unref (attributes);
}
+typedef struct {
+ const SecretSchema *schema;
+ GHashTable *attributes;
+ SecretSearchFlags flags;
+} SearchClosure;
+
+static void
+search_closure_free (gpointer data)
+{
+ SearchClosure *closure = data;
+ _secret_schema_unref_if_nonstatic (closure->schema);
+ g_hash_table_unref (closure->attributes);
+ g_slice_free (SearchClosure, closure);
+}
+
+static void
+object_list_free (gpointer data)
+{
+ GList *list = data;
+ g_list_free_full (list, g_object_unref);
+}
+
+static void
+on_search (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GTask *task = G_TASK (user_data);
+ SecretBackend *backend = SECRET_BACKEND (source);
+ SecretBackendInterface *iface;
+ GError *error = NULL;
+ GList *items;
+
+ iface = SECRET_BACKEND_GET_IFACE (backend);
+ g_return_if_fail (iface->search_finish != NULL);
+
+ items = iface->search_finish (backend, result, &error);
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ g_task_return_pointer (task, items, object_list_free);
+ g_object_unref (task);
+}
+
+static void
+on_search_backend (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GTask *task = G_TASK (user_data);
+ SearchClosure *search = g_task_get_task_data (task);
+ SecretBackend *backend;
+ SecretBackendInterface *iface;
+ GError *error = NULL;
+
+ backend = secret_backend_get_finish (result, &error);
+ if (backend == NULL) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ iface = SECRET_BACKEND_GET_IFACE (backend);
+ g_return_if_fail (iface->search != NULL);
+
+ iface->search (backend,
+ search->schema, search->attributes, search->flags,
+ g_task_get_cancellable (task),
+ on_search,
+ task);
+}
+
/**
* secret_password_searchv: (rename-to secret_password_search)
* @schema: (nullable): the schema for attributes
- * @attributes: (element-type utf8 utf8): the attribute keys and values
+ * @attributes: (element-type utf8 utf8) (transfer full): the attribute keys and values
* @flags: search option flags
* @cancellable: optional cancellation object
- * @callback: called when the operation completes
+ * @callback: (scope async): called when the operation completes
* @user_data: data to be passed to the callback
*
* Search for items in the secret service.
@@ -1246,6 +1575,9 @@ secret_password_searchv (const SecretSchema *schema,
GAsyncReadyCallback callback,
gpointer user_data)
{
+ SearchClosure *search;
+ GTask *task;
+
g_return_if_fail (attributes != NULL);
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
@@ -1253,8 +1585,16 @@ secret_password_searchv (const SecretSchema *schema,
if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
return;
- secret_service_search (NULL, schema, attributes, flags,
- cancellable, callback, user_data);
+ task = g_task_new (NULL, cancellable, callback, user_data);
+ search = g_slice_new0 (SearchClosure);
+ search->schema = _secret_schema_ref_if_nonstatic (schema);
+ search->attributes = g_hash_table_ref (attributes);
+ search->flags = flags;
+ g_task_set_task_data (task, search, search_closure_free);
+
+ secret_backend_get (SECRET_SERVICE_NONE,
+ cancellable,
+ on_search_backend, task);
}
/**
@@ -1274,8 +1614,9 @@ secret_password_search_finish (GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
- return secret_service_search_finish (NULL, result, error);
+ return g_task_propagate_pointer (G_TASK (result), error);
}
/**
diff --git a/libsecret/secret-service.c b/libsecret/secret-service.c
index 6dea0d1..36d2feb 100644
--- a/libsecret/secret-service.c
+++ b/libsecret/secret-service.c
@@ -15,6 +15,7 @@
#include "config.h"
+#include "secret-backend.h"
#include "secret-collection.h"
#include "secret-dbus-generated.h"
#include "secret-item.h"
@@ -135,14 +136,24 @@ static GInitableIface *secret_service_initable_parent_iface = NULL;
static GAsyncInitableIface *secret_service_async_initable_parent_iface = NULL;
+static SecretBackendInterface *secret_service_backend_parent_iface = NULL;
+
static void secret_service_initable_iface (GInitableIface *iface);
static void secret_service_async_initable_iface (GAsyncInitableIface *iface);
+static void secret_service_backend_iface (SecretBackendInterface *iface);
+
G_DEFINE_TYPE_WITH_CODE (SecretService, secret_service, G_TYPE_DBUS_PROXY,
G_ADD_PRIVATE (SecretService)
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, secret_service_initable_iface);
G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, secret_service_async_initable_iface);
+ G_IMPLEMENT_INTERFACE (SECRET_TYPE_BACKEND, secret_service_backend_iface);
+ _secret_backend_ensure_extension_point ();
+ g_io_extension_point_implement (SECRET_BACKEND_EXTENSION_POINT_NAME,
+ g_define_type_id,
+ "service",
+ 0)
);
static SecretService *
@@ -180,6 +191,8 @@ service_uncache_instance (SecretService *which)
if (watch != 0)
g_bus_unwatch_name (watch);
+ _secret_backend_uncache_instance ();
+
return matched;
}
@@ -509,6 +522,38 @@ secret_service_real_get_item_gtype (SecretService *self)
return klass->item_gtype;
}
+static const gchar *
+get_default_bus_name (void)
+{
+ const gchar *bus_name;
+
+ bus_name = g_getenv ("SECRET_SERVICE_BUS_NAME");
+ if (bus_name == NULL)
+ bus_name = SECRET_SERVICE_BUS_NAME;
+
+ return bus_name;
+}
+
+static GObject *
+secret_service_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GObject *object;
+
+ object = G_OBJECT_CLASS (secret_service_parent_class)->
+ constructor (type, n_construct_properties, construct_properties);
+ g_object_set (object,
+ "g-flags", G_DBUS_PROXY_FLAGS_NONE,
+ "g-interface-info", _secret_gen_service_interface_info (),
+ "g-name", get_default_bus_name (),
+ "g-bus-type", G_BUS_TYPE_SESSION,
+ "g-object-path", SECRET_SERVICE_PATH,
+ "g-interface-name", SECRET_SERVICE_INTERFACE,
+ NULL);
+ return object;
+}
+
static void
secret_service_class_init (SecretServiceClass *klass)
{
@@ -519,6 +564,7 @@ secret_service_class_init (SecretServiceClass *klass)
object_class->set_property = secret_service_set_property;
object_class->dispose = secret_service_dispose;
object_class->finalize = secret_service_finalize;
+ object_class->constructor = secret_service_constructor;
proxy_class->g_properties_changed = secret_service_properties_changed;
proxy_class->g_signal = secret_service_signal;
@@ -538,10 +584,7 @@ secret_service_class_init (SecretServiceClass *klass)
* A set of flags describing which parts of the secret service have
* been initialized.
*/
- g_object_class_install_property (object_class, PROP_FLAGS,
- g_param_spec_flags ("flags", "Flags", "Service flags",
- secret_service_flags_get_type (), SECRET_SERVICE_NONE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+ g_object_class_override_property (object_class, PROP_FLAGS, "flags");
/**
* SecretService:collections:
@@ -745,16 +788,160 @@ secret_service_async_initable_iface (GAsyncInitableIface *iface)
iface->init_finish = secret_service_async_initable_init_finish;
}
-static const gchar *
-get_default_bus_name (void)
+static void
+secret_service_real_ensure_for_flags (SecretBackend *self,
+ SecretBackendFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- const gchar *bus_name;
+ GTask *task;
+ InitClosure *closure;
- bus_name = g_getenv ("SECRET_SERVICE_BUS_NAME");
- if (bus_name == NULL)
- bus_name = SECRET_SERVICE_BUS_NAME;
+ g_return_if_fail (SECRET_IS_SERVICE (self));
- return bus_name;
+ task = g_task_new (self, cancellable, callback, user_data);
+ closure = g_slice_new0 (InitClosure);
+ g_task_set_task_data (task, closure, init_closure_free);
+ service_ensure_for_flags_async (SECRET_SERVICE (self), flags, task);
+ g_object_unref (task);
+}
+
+static gboolean
+secret_service_real_ensure_for_flags_finish (SecretBackend *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
+
+ if (!g_task_propagate_boolean (G_TASK (result), error)) {
+ _secret_util_strip_remote_error (error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+secret_service_real_store (SecretBackend *self,
+ const SecretSchema *schema,
+ GHashTable *attributes,
+ const gchar *collection,
+ const gchar *label,
+ SecretValue *value,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_return_if_fail (SECRET_IS_SERVICE (self));
+
+ secret_service_store (SECRET_SERVICE (self), schema, attributes,
+ collection, label, value,
+ cancellable, callback, user_data);
+}
+
+static gboolean
+secret_service_real_store_finish (SecretBackend *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
+
+ return secret_service_store_finish (SECRET_SERVICE (self),
+ result, error);
+}
+
+static void
+secret_service_real_lookup (SecretBackend *self,
+ const SecretSchema *schema,
+ GHashTable *attributes,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_return_if_fail (SECRET_IS_SERVICE (self));
+
+ secret_service_lookup (SECRET_SERVICE (self), schema, attributes,
+ cancellable, callback, user_data);
+}
+
+static SecretValue *
+secret_service_real_lookup_finish (SecretBackend *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
+
+ return secret_service_lookup_finish (SECRET_SERVICE (self),
+ result, error);
+}
+
+static void
+secret_service_real_clear (SecretBackend *self,
+ const SecretSchema *schema,
+ GHashTable *attributes,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_return_if_fail (SECRET_IS_SERVICE (self));
+
+ secret_service_clear (SECRET_SERVICE (self), schema, attributes,
+ cancellable, callback, user_data);
+}
+
+static gboolean
+secret_service_real_clear_finish (SecretBackend *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
+
+ return secret_service_clear_finish (SECRET_SERVICE (self),
+ result, error);
+}
+
+static void
+secret_service_real_search (SecretBackend *self,
+ const SecretSchema *schema,
+ GHashTable *attributes,
+ SecretSearchFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_return_if_fail (SECRET_IS_SERVICE (self));
+
+ secret_service_search (SECRET_SERVICE (self), schema, attributes, flags,
+ cancellable, callback, user_data);
+}
+
+static GList *
+secret_service_real_search_finish (SecretBackend *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
+
+ return secret_service_search_finish (SECRET_SERVICE (self),
+ result, error);
+}
+
+static void
+secret_service_backend_iface (SecretBackendInterface *iface)
+{
+ secret_service_backend_parent_iface = g_type_interface_peek_parent (iface);
+
+ iface->ensure_for_flags = secret_service_real_ensure_for_flags;
+ iface->ensure_for_flags_finish = secret_service_real_ensure_for_flags_finish;
+ iface->store = secret_service_real_store;
+ iface->store_finish = secret_service_real_store_finish;
+ iface->lookup = secret_service_real_lookup;
+ iface->lookup_finish = secret_service_real_lookup_finish;
+ iface->clear = secret_service_real_clear;
+ iface->clear_finish = secret_service_real_clear_finish;
+ iface->search = secret_service_real_search;
+ iface->search_finish = secret_service_real_search_finish;
}
/**
@@ -788,13 +975,7 @@ secret_service_get (SecretServiceFlags flags,
if (service == NULL) {
g_async_initable_new_async (SECRET_TYPE_SERVICE, G_PRIORITY_DEFAULT,
cancellable, callback, user_data,
- "g-flags", G_DBUS_PROXY_FLAGS_NONE,
- "g-interface-info", _secret_gen_service_interface_info (),
- "g-name", get_default_bus_name (),
- "g-bus-type", G_BUS_TYPE_SESSION,
- "g-object-path", SECRET_SERVICE_PATH,
- "g-interface-name", SECRET_SERVICE_INTERFACE,
- "flags", flags,
+ "flags", flags,
NULL);
/* Just have to ensure that the service matches flags */
@@ -890,12 +1071,6 @@ secret_service_get_sync (SecretServiceFlags flags,
if (service == NULL) {
service = g_initable_new (SECRET_TYPE_SERVICE, cancellable, error,
- "g-flags", G_DBUS_PROXY_FLAGS_NONE,
- "g-interface-info", _secret_gen_service_interface_info (),
- "g-name", get_default_bus_name (),
- "g-bus-type", G_BUS_TYPE_SESSION,
- "g-object-path", SECRET_SERVICE_PATH,
- "g-interface-name", SECRET_SERVICE_INTERFACE,
"flags", flags,
NULL);
@@ -970,12 +1145,6 @@ secret_service_open (GType service_gtype,
g_async_initable_new_async (service_gtype, G_PRIORITY_DEFAULT,
cancellable, callback, user_data,
- "g-flags", G_DBUS_PROXY_FLAGS_NONE,
- "g-interface-info", _secret_gen_service_interface_info (),
- "g-name", service_bus_name,
- "g-bus-type", G_BUS_TYPE_SESSION,
- "g-object-path", SECRET_SERVICE_PATH,
- "g-interface-name", SECRET_SERVICE_INTERFACE,
"flags", flags,
NULL);
}
@@ -1052,12 +1221,6 @@ secret_service_open_sync (GType service_gtype,
service_bus_name = get_default_bus_name ();
return g_initable_new (service_gtype, cancellable, error,
- "g-flags", G_DBUS_PROXY_FLAGS_NONE,
- "g-interface-info", _secret_gen_service_interface_info (),
- "g-name", service_bus_name,
- "g-bus-type", G_BUS_TYPE_SESSION,
- "g-object-path", SECRET_SERVICE_PATH,
- "g-interface-name", SECRET_SERVICE_INTERFACE,
"flags", flags,
NULL);
}