From 938640ae52cab0b602975ff837728160c03aa86a Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Mon, 17 Jun 2019 15:30:00 +0200 Subject: [PATCH 1/9] secret-retrievable: New interface to represent read-only item This is a ground work for adding a local storage backend. As SecretItem is derived from GDBusProxy, it cannot be simply exposed to the application through the secret_password_search() if the item is not backed by the DBus API. This adds an abstract interface representing a read-only view of a secret item for that purpose. --- docs/reference/libsecret/libsecret-docs.sgml | 1 + .../libsecret/libsecret-sections.txt | 15 + libsecret/Makefile.am | 2 + libsecret/meson.build | 4 + libsecret/secret-retrievable.c | 307 ++++++++++++++++++ libsecret/secret-retrievable.h | 64 ++++ libsecret/secret.h | 1 + 7 files changed, 394 insertions(+) create mode 100644 libsecret/secret-retrievable.c create mode 100644 libsecret/secret-retrievable.h diff --git a/docs/reference/libsecret/libsecret-docs.sgml b/docs/reference/libsecret/libsecret-docs.sgml index 6ce3dba..0381c5a 100644 --- a/docs/reference/libsecret/libsecret-docs.sgml +++ b/docs/reference/libsecret/libsecret-docs.sgml @@ -26,6 +26,7 @@ + diff --git a/docs/reference/libsecret/libsecret-sections.txt b/docs/reference/libsecret/libsecret-sections.txt index 2ae7250..17ee05f 100644 --- a/docs/reference/libsecret/libsecret-sections.txt +++ b/docs/reference/libsecret/libsecret-sections.txt @@ -137,6 +137,21 @@ secret_password_wipe secret_password_free +
+secret-retrievable +libsecret/secret.h +SECRET_TYPE_RETRIEVABLE +SecretRetrievable +SecretRetrievableInterface +secret_retrievable_get_attributes +secret_retrievable_get_created +secret_retrievable_get_label +secret_retrievable_get_modified +secret_retrievable_retrieve_secret +secret_retrievable_retrieve_secret_finish +secret_retrievable_retrieve_secret_sync +
+
secret-schema libsecret/secret.h diff --git a/libsecret/Makefile.am b/libsecret/Makefile.am index c91b733..0e661b8 100644 --- a/libsecret/Makefile.am +++ b/libsecret/Makefile.am @@ -12,6 +12,7 @@ libsecret_HEADS = \ libsecret/secret-password.h \ libsecret/secret-paths.h \ libsecret/secret-prompt.h \ + libsecret/secret-retrievable.h \ libsecret/secret-schema.h \ libsecret/secret-schemas.h \ libsecret/secret-service.h \ @@ -42,6 +43,7 @@ libsecret_PUBLIC = \ libsecret/secret-methods.c \ libsecret/secret-password.h libsecret/secret-password.c \ libsecret/secret-prompt.h libsecret/secret-prompt.c \ + libsecret/secret-retrievable.h libsecret/secret-retrievable.c \ libsecret/secret-schema.h libsecret/secret-schema.c \ libsecret/secret-schemas.h libsecret/secret-schemas.c \ libsecret/secret-service.h libsecret/secret-service.c \ diff --git a/libsecret/meson.build b/libsecret/meson.build index f35c396..60fa11e 100644 --- a/libsecret/meson.build +++ b/libsecret/meson.build @@ -7,6 +7,7 @@ libsecret_sources = [ 'secret-methods.c', 'secret-password.c', 'secret-prompt.c', + 'secret-retrievable.c', 'secret-schema.c', 'secret-schemas.c', 'secret-service.c', @@ -24,6 +25,7 @@ libsecret_headers = [ 'secret-password.h', 'secret-paths.h', 'secret-prompt.h', + 'secret-retrievable.h', 'secret-schema.h', 'secret-schemas.h', 'secret-service.h', @@ -104,6 +106,8 @@ libsecret_gir_sources = [ 'secret-paths.h', 'secret-prompt.c', 'secret-prompt.h', + 'secret-retrievable.c', + 'secret-retrievable.h', 'secret-schema.c', 'secret-schema.h', 'secret-schemas.c', diff --git a/libsecret/secret-retrievable.c b/libsecret/secret-retrievable.c new file mode 100644 index 0000000..caa063b --- /dev/null +++ b/libsecret/secret-retrievable.c @@ -0,0 +1,307 @@ +/* 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-retrievable.h" +#include "secret-private.h" + +/** + * SECTION:secret-retrievable + * @title: SecretRetrievable + * @short_description: A read-only secret item + * + * #SecretRetrievable provides a read-only view of a secret item + * stored in the Secret Service. + * + * Each item has a value, represented by a #SecretValue, which can be + * retrieved by secret_retrievable_retrieve_secret() and + * secret_retrievable_retrieve_secret_finish(). + * + * Stability: Stable + */ + +/** + * SecretRetrievable: + * + * An object representing a read-only view of a secret item in the + * Secret Service. + * + * Since: 0.19.0 + */ + +/** + * SecretRetrievableInterface: + * @parent_iface: the parent interface + * @retrieve_secret: implementation of secret_retrievable_retrieve_secret(), + * required + * @retrieve_secret_finish: implementation of + * secret_retrievable_retrieve_secret_finish(), required + * + * The interface for #SecretRetrievable. + * + * Since: 0.19.0 + */ + +G_DEFINE_INTERFACE (SecretRetrievable, secret_retrievable, G_TYPE_OBJECT); + +static void +secret_retrievable_default_init (SecretRetrievableInterface *iface) +{ + /** + * SecretRetrievable:attributes: (type GLib.HashTable(utf8,utf8)) (transfer full) + * + * The attributes set on this item. Attributes are used to locate an + * item. They are not guaranteed to be stored or transferred securely. + * + * Since: 0.19.0 + */ + g_object_interface_install_property (iface, + g_param_spec_boxed ("attributes", "Attributes", "Item attributes", + G_TYPE_HASH_TABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * SecretRetrievable:label: + * + * The human readable label for the item. + * + * Since: 0.19.0 + */ + g_object_interface_install_property (iface, + g_param_spec_string ("label", "Label", "Item label", + NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * SecretRetrievable:created: + * + * The date and time (in seconds since the UNIX epoch) that this + * item was created. + * + * Since: 0.19.0 + */ + g_object_interface_install_property (iface, + g_param_spec_uint64 ("created", "Created", "Item creation date", + 0UL, G_MAXUINT64, 0UL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * SecretRetrievable:modified: + * + * The date and time (in seconds since the UNIX epoch) that this + * item was last modified. + * + * Since: 0.19.0 + */ + g_object_interface_install_property (iface, + g_param_spec_uint64 ("modified", "Modified", "Item modified date", + 0UL, G_MAXUINT64, 0UL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +} + +/** + * secret_retrievable_retrieve_secret: + * @self: a retrievable object + * @cancellable: (nullable): optional cancellation object + * @callback: called when the operation completes + * @user_data: data to pass to the callback + * + * Retrieve the secret value of this object. + * + * Each retrievable object has a single secret which might be a + * password or some other secret binary value. + * + * This function returns immediately and completes asynchronously. + * + * Since: 0.19.0 + */ +void +secret_retrievable_retrieve_secret (SecretRetrievable *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + SecretRetrievableInterface *iface; + + g_return_if_fail (SECRET_IS_RETRIEVABLE (self)); + iface = SECRET_RETRIEVABLE_GET_IFACE (self); + g_return_if_fail (iface->retrieve_secret != NULL); + iface->retrieve_secret (self, cancellable, callback, user_data); +} + +/** + * secret_retrievable_retrieve_secret_finish: + * @self: a retrievable object + * @result: asynchronous result passed to callback + * @error: location to place error on failure + * + * Complete asynchronous operation to retrieve the secret value of this object. + * + * Returns: (transfer full) (nullable): the secret value which should be + * released with secret_value_unref(), or %NULL + * + * Since: 0.19.0 + */ +SecretValue * +secret_retrievable_retrieve_secret_finish (SecretRetrievable *self, + GAsyncResult *result, + GError **error) +{ + SecretRetrievableInterface *iface; + + g_return_val_if_fail (SECRET_IS_RETRIEVABLE (self), NULL); + iface = SECRET_RETRIEVABLE_GET_IFACE (self); + g_return_val_if_fail (iface->retrieve_secret_finish != NULL, NULL); + return iface->retrieve_secret_finish (self, result, error); +} + +/** + * secret_retrievable_retrieve_secret_sync: + * @self: a retrievable object + * @cancellable: (nullable): optional cancellation object + * @error: location to place error on failure + * + * Retrieve the secret value of this object synchronously. + * + * Each retrievable object has a single secret which might be a + * password or some other secret binary value. + * + * This method may block indefinitely and should not be used in user interface + * threads. + * + * Returns: (transfer full) (nullable): the secret value which should be + * released with secret_value_unref(), or %NULL + * + * Since: 0.19.0 + */ +SecretValue * +secret_retrievable_retrieve_secret_sync (SecretRetrievable *self, + GCancellable *cancellable, + GError **error) +{ + SecretSync *sync; + SecretValue *value; + + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + sync = _secret_sync_new (); + g_main_context_push_thread_default (sync->context); + + secret_retrievable_retrieve_secret (self, + cancellable, + _secret_sync_on_result, sync); + + g_main_loop_run (sync->loop); + + value = secret_retrievable_retrieve_secret_finish (self, + sync->result, + error); + + g_main_context_pop_thread_default (sync->context); + _secret_sync_free (sync); + + return value; +} + +/** + * secret_retrievable_get_attributes: + * @self: a retrievable object + * + * Get the attributes of this object. + * + * The attributes are a mapping of string keys to string values. + * Attributes are used to search for items. Attributes are not stored + * or transferred securely by the secret service. + * + * Do not modify the attribute returned by this method. + * + * Returns: (transfer full) (element-type utf8 utf8): a new reference + * to the attributes, which should not be modified, and + * released with g_hash_table_unref() + * + * Since: 0.19.0 + */ +GHashTable * +secret_retrievable_get_attributes (SecretRetrievable *self) +{ + GHashTable *value; + + g_return_val_if_fail (SECRET_IS_RETRIEVABLE (self), NULL); + + g_object_get (G_OBJECT (self), "attributes", &value, NULL); + return value; +} + +/** + * secret_retrievable_get_label: + * @self: a retrievable object + * + * Get the label of this item. + * + * Returns: (transfer full): the label, which should be freed with g_free() + * + * Since: 0.19.0 + */ +gchar * +secret_retrievable_get_label (SecretRetrievable *self) +{ + gchar *value; + + g_return_val_if_fail (SECRET_IS_RETRIEVABLE (self), NULL); + + g_object_get (G_OBJECT (self), "label", &value, NULL); + return value; +} + +/** + * secret_retrievable_get_created: + * @self: a retrievable object + * + * Get the created date and time of the object. The return value is + * the number of seconds since the unix epoch, January 1st 1970. + * + * Returns: the created date and time + * + * Since: 0.19.0 + */ +guint64 +secret_retrievable_get_created (SecretRetrievable *self) +{ + guint64 value; + + g_return_val_if_fail (SECRET_IS_RETRIEVABLE (self), 0); + + g_object_get (G_OBJECT (self), "created", &value, NULL); + return value; +} + +/** + * secret_retrievable_get_modified: + * @self: a retrievable object + * + * Get the modified date and time of the object. The return value is + * the number of seconds since the unix epoch, January 1st 1970. + * + * Returns: the modified date and time + * + * Since: 0.19.0 + */ +guint64 +secret_retrievable_get_modified (SecretRetrievable *self) +{ + guint64 value; + + g_return_val_if_fail (SECRET_IS_RETRIEVABLE (self), 0); + + g_object_get (G_OBJECT (self), "modified", &value, NULL); + return value; +} diff --git a/libsecret/secret-retrievable.h b/libsecret/secret-retrievable.h new file mode 100644 index 0000000..8b66cef --- /dev/null +++ b/libsecret/secret-retrievable.h @@ -0,0 +1,64 @@ +/* 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 can be included directly." +#endif + +#ifndef __SECRET_RETRIEVABLE_H__ +#define __SECRET_RETRIEVABLE_H__ + +#include +#include "secret-value.h" + +G_BEGIN_DECLS + +#define SECRET_TYPE_RETRIEVABLE secret_retrievable_get_type () +G_DECLARE_INTERFACE (SecretRetrievable, secret_retrievable, SECRET, RETRIEVABLE, GObject) + +struct _SecretRetrievableInterface +{ + GTypeInterface parent_iface; + + void (*retrieve_secret) (SecretRetrievable *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + SecretValue *(*retrieve_secret_finish) (SecretRetrievable *self, + GAsyncResult *result, + GError **error); +}; + +void secret_retrievable_retrieve_secret (SecretRetrievable *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +SecretValue *secret_retrievable_retrieve_secret_finish (SecretRetrievable *self, + GAsyncResult *result, + GError **error); + +SecretValue *secret_retrievable_retrieve_secret_sync (SecretRetrievable *self, + GCancellable *cancellable, + GError **error); + +GHashTable *secret_retrievable_get_attributes (SecretRetrievable *self); +gchar *secret_retrievable_get_label (SecretRetrievable *self); +guint64 secret_retrievable_get_created (SecretRetrievable *self); +guint64 secret_retrievable_get_modified (SecretRetrievable *self); + + +G_END_DECLS + +#endif /* __SECRET_RETRIEVABLE_H__ */ diff --git a/libsecret/secret.h b/libsecret/secret.h index 8d11324..7e6e7c6 100644 --- a/libsecret/secret.h +++ b/libsecret/secret.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include From 092d4ef47dfbc3e37fdca6c924a9421f3b098665 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Mon, 17 Jun 2019 15:30:00 +0200 Subject: [PATCH 2/9] secret-item: Implement SecretRetrievableInterface --- libsecret/secret-item.c | 71 ++++++++++++++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 12 deletions(-) diff --git a/libsecret/secret-item.c b/libsecret/secret-item.c index d447bcd..a5eb7cf 100644 --- a/libsecret/secret-item.c +++ b/libsecret/secret-item.c @@ -19,6 +19,7 @@ #include "secret-item.h" #include "secret-paths.h" #include "secret-private.h" +#include "secret-retrievable.h" #include "secret-service.h" #include "secret-types.h" #include "secret-value.h" @@ -105,16 +106,21 @@ struct _SecretItemPrivate { gint disposed; }; +static SecretRetrievableInterface *secret_item_retrievable_parent_iface = NULL; + static GInitableIface *secret_item_initable_parent_iface = NULL; static GAsyncInitableIface *secret_item_async_initable_parent_iface = NULL; +static void secret_item_retrievable_iface (SecretRetrievableInterface *iface); + static void secret_item_initable_iface (GInitableIface *iface); static void secret_item_async_initable_iface (GAsyncInitableIface *iface); G_DEFINE_TYPE_WITH_CODE (SecretItem, secret_item, G_TYPE_DBUS_PROXY, G_ADD_PRIVATE (SecretItem) + G_IMPLEMENT_INTERFACE (SECRET_TYPE_RETRIEVABLE, secret_item_retrievable_iface); G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, secret_item_initable_iface); G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, secret_item_async_initable_iface); ); @@ -355,9 +361,7 @@ secret_item_class_init (SecretItemClass *klass) * The attributes set on this item. Attributes are used to locate an * item. They are not guaranteed to be stored or transferred securely. */ - g_object_class_install_property (gobject_class, PROP_ATTRIBUTES, - g_param_spec_boxed ("attributes", "Attributes", "Item attributes", - G_TYPE_HASH_TABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_override_property (gobject_class, PROP_ATTRIBUTES, "attributes"); /** * SecretItem:label: @@ -368,9 +372,7 @@ secret_item_class_init (SecretItemClass *klass) * set asynchronously. To properly track the changing of the label use the * secret_item_set_label() function. */ - g_object_class_install_property (gobject_class, PROP_LABEL, - g_param_spec_string ("label", "Label", "Item label", - NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_override_property (gobject_class, PROP_LABEL, "label"); /** * SecretItem:locked: @@ -391,9 +393,7 @@ secret_item_class_init (SecretItemClass *klass) * The date and time (in seconds since the UNIX epoch) that this * item was created. */ - g_object_class_install_property (gobject_class, PROP_CREATED, - g_param_spec_uint64 ("created", "Created", "Item creation date", - 0UL, G_MAXUINT64, 0UL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_override_property (gobject_class, PROP_CREATED, "created"); /** * SecretItem:modified: @@ -401,9 +401,7 @@ secret_item_class_init (SecretItemClass *klass) * The date and time (in seconds since the UNIX epoch) that this * item was last modified. */ - g_object_class_install_property (gobject_class, PROP_MODIFIED, - g_param_spec_uint64 ("modified", "Modified", "Item modified date", - 0UL, G_MAXUINT64, 0UL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_override_property (gobject_class, PROP_MODIFIED, "modified"); } typedef struct { @@ -1320,6 +1318,55 @@ secret_item_load_secret_sync (SecretItem *self, return result; } +static void +on_retrieve_load (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + SecretItem *self = SECRET_ITEM (source_object); + GTask *task = G_TASK (user_data); + GError *error = NULL; + + if (secret_item_load_secret_finish (self, res, &error)) { + g_task_return_pointer (task, + secret_item_get_secret (self), + secret_value_unref); + g_object_unref (task); + } else { + g_task_return_error (task, error); + g_object_unref (task); + } +} + +static void +secret_item_retrieve_secret (SecretRetrievable *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task = g_task_new (self, cancellable, callback, user_data); + + secret_item_load_secret (SECRET_ITEM (self), cancellable, on_retrieve_load, task); +} + +static SecretValue * +secret_item_retrieve_secret_finish (SecretRetrievable *self, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, self), NULL); + + return g_task_propagate_pointer (G_TASK (result), error); +} + +static void +secret_item_retrievable_iface (SecretRetrievableInterface *iface) +{ + secret_item_retrievable_parent_iface = g_type_interface_peek_parent (iface); + iface->retrieve_secret = secret_item_retrieve_secret; + iface->retrieve_secret_finish = secret_item_retrieve_secret_finish; +} + typedef struct { SecretService *service; GCancellable *cancellable; From 5fedca8ffc1e57c55ee564c39d1c2d579a15f01f Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Mon, 17 Jun 2019 15:30:00 +0200 Subject: [PATCH 3/9] secret-password: Add search functions This adds a set of functions that expose secret_service_search* from the simple API. --- .../libsecret/libsecret-sections.txt | 5 + libsecret/secret-password.c | 220 ++++++++++++++++++ libsecret/secret-password.h | 29 +++ libsecret/secret-service.h | 7 - libsecret/secret-types.h | 7 + libsecret/test-password.c | 88 +++++++ 6 files changed, 349 insertions(+), 7 deletions(-) diff --git a/docs/reference/libsecret/libsecret-sections.txt b/docs/reference/libsecret/libsecret-sections.txt index 17ee05f..b561366 100644 --- a/docs/reference/libsecret/libsecret-sections.txt +++ b/docs/reference/libsecret/libsecret-sections.txt @@ -133,6 +133,11 @@ secret_password_clearv secret_password_clear_finish secret_password_clear_sync secret_password_clearv_sync +secret_password_search +secret_password_search_finish +secret_password_search_sync +secret_password_searchv +secret_password_searchv_sync secret_password_wipe secret_password_free
diff --git a/libsecret/secret-password.c b/libsecret/secret-password.c index 149995d..fc0ea0c 100644 --- a/libsecret/secret-password.c +++ b/libsecret/secret-password.c @@ -17,6 +17,7 @@ #include "secret-attributes.h" #include "secret-password.h" #include "secret-private.h" +#include "secret-retrievable.h" #include "secret-value.h" #include @@ -844,6 +845,225 @@ secret_password_clearv_sync (const SecretSchema *schema, return result; } +/** + * secret_password_search: (skip) + * @schema: the schema for the attributes + * @flags: search option flags + * @cancellable: optional cancellation object + * @callback: called when the operation completes + * @user_data: data to be passed to the callback + * @...: the attribute keys and values, terminated with %NULL + * + * Search for items in the secret service. + * + * The variable argument list should contain pairs of a) The attribute name as + * a null-terminated string, followed by b) attribute value, either a character + * string, an int number, or a gboolean value, as defined in the password + * @schema. The list of attribtues should be terminated with a %NULL. + * + * This method will return immediately and complete asynchronously. + * + * Since: 0.19.0 + */ +void +secret_password_search (const SecretSchema *schema, + SecretSearchFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data, + ...) +{ + GHashTable *attributes; + va_list va; + + g_return_if_fail (schema != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + va_start (va, user_data); + attributes = secret_attributes_buildv (schema, va); + va_end (va); + + /* Precondition failed, already warned */ + if (!attributes) + return; + + secret_password_searchv (schema, attributes, flags, cancellable, + callback, user_data); + + g_hash_table_unref (attributes); +} + +/** + * secret_password_searchv: (rename-to secret_password_search) + * @schema: the schema for attributes + * @attributes: (element-type utf8 utf8): the attribute keys and values + * @flags: search option flags + * @cancellable: optional cancellation object + * @callback: called when the operation completes + * @user_data: data to be passed to the callback + * + * Search for items in the secret service. + * + * The @attributes should be a set of key and value string pairs. + * + * This method will return immediately and complete asynchronously. + * + * Since: 0.19.0 + */ +void +secret_password_searchv (const SecretSchema *schema, + GHashTable *attributes, + SecretSearchFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_return_if_fail (schema != NULL); + g_return_if_fail (attributes != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + /* Warnings raised already */ + if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) + return; + + secret_service_search (NULL, schema, attributes, flags, + cancellable, callback, user_data); +} + +/** + * secret_password_search_finish: + * @result: the asynchronous result passed to the callback + * @error: location to place an error on failure + * + * Finish an asynchronous operation to search for items in the secret service. + * + * Returns: (transfer full) (element-type Secret.Retrievable): a list of + * #SecretRetrievable containing attributes of the matched items + * + * Since: 0.19.0 + */ +GList * +secret_password_search_finish (GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + return secret_service_search_finish (NULL, result, error); +} + +/** + * secret_password_search_sync: (skip) + * @schema: the schema for the attributes + * @flags: search option flags + * @cancellable: optional cancellation object + * @error: location to place an error on failure + * @...: the attribute keys and values, terminated with %NULL + * + * Search for items in the secret service. + * + * The variable argument list should contain pairs of a) The attribute name as + * a null-terminated string, followed by b) attribute value, either a character + * string, an int number, or a gboolean value, as defined in the password + * @schema. The list of attributes should be terminated with a %NULL. + * + * If no secret is found then %NULL is returned. + * + * This method may block indefinitely and should not be used in user interface + * threads. + * + * Returns: (transfer full) (element-type Secret.Retrievable): a list of + * #SecretRetrievable containing attributes of the matched items + * + * Since: 0.19.0 + */ +GList * +secret_password_search_sync (const SecretSchema *schema, + SecretSearchFlags flags, + GCancellable *cancellable, + GError **error, + ...) +{ + GHashTable *attributes; + GList *items; + va_list va; + + g_return_val_if_fail (schema != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + va_start (va, error); + attributes = secret_attributes_buildv (schema, va); + va_end (va); + + /* Precondition failed, already warned */ + if (!attributes) + return NULL; + + items = secret_password_searchv_sync (schema, attributes, flags, + cancellable, error); + + g_hash_table_unref (attributes); + + return items; +} + +/** + * secret_password_searchv_sync: (rename-to secret_password_search_sync) + * @schema: the schema for attributes + * @attributes: (element-type utf8 utf8): the attribute keys and values + * @flags: search option flags + * @cancellable: optional cancellation object + * @error: location to place an error on failure + * + * Search for items in the secret service. + * + * The @attributes should be a set of key and value string pairs. + * + * If no secret is found then %NULL is returned. + * + * This method may block indefinitely and should not be used in user interface + * threads. + * + * Returns: (transfer full) (element-type Secret.Retrievable): a list of + * #SecretRetrievable containing attributes of the matched items + * + * Since: 0.19.0 + */ +GList * +secret_password_searchv_sync (const SecretSchema *schema, + GHashTable *attributes, + SecretSearchFlags flags, + GCancellable *cancellable, + GError **error) +{ + SecretSync *sync; + GList *items; + + g_return_val_if_fail (schema != NULL, NULL); + g_return_val_if_fail (attributes != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* Warnings raised already */ + if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) + return NULL; + + sync = _secret_sync_new (); + g_main_context_push_thread_default (sync->context); + + secret_password_searchv (schema, attributes, flags, cancellable, + _secret_sync_on_result, sync); + + g_main_loop_run (sync->loop); + + items = secret_password_search_finish (sync->result, error); + + g_main_context_pop_thread_default (sync->context); + _secret_sync_free (sync); + + return items; +} + /** * secret_password_free: (skip) * @password: (allow-none): password to free diff --git a/libsecret/secret-password.h b/libsecret/secret-password.h index d47abb3..725d11b 100644 --- a/libsecret/secret-password.h +++ b/libsecret/secret-password.h @@ -126,6 +126,35 @@ gboolean secret_password_clearv_sync (const SecretSchema *sche GCancellable *cancellable, GError **error); +void secret_password_search (const SecretSchema *schema, + SecretSearchFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data, + ...) G_GNUC_NULL_TERMINATED; + +void secret_password_searchv (const SecretSchema *schema, + GHashTable *attributes, + SecretSearchFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GList * secret_password_search_sync (const SecretSchema *schema, + SecretSearchFlags flags, + GCancellable *cancellable, + GError **error, + ...) G_GNUC_NULL_TERMINATED; + +GList * secret_password_searchv_sync (const SecretSchema *schema, + GHashTable *attributes, + SecretSearchFlags flags, + GCancellable *cancellable, + GError **error); + +GList * secret_password_search_finish (GAsyncResult *result, + GError **error); + void secret_password_free (gchar *password); void secret_password_wipe (gchar *password); diff --git a/libsecret/secret-service.h b/libsecret/secret-service.h index 4c3a827..44cbc1e 100644 --- a/libsecret/secret-service.h +++ b/libsecret/secret-service.h @@ -35,13 +35,6 @@ typedef enum { SECRET_SERVICE_LOAD_COLLECTIONS = 1 << 2, } SecretServiceFlags; -typedef enum { - SECRET_SEARCH_NONE = 0, - SECRET_SEARCH_ALL = 1 << 1, - SECRET_SEARCH_UNLOCK = 1 << 2, - SECRET_SEARCH_LOAD_SECRETS = 1 << 3, -} SecretSearchFlags; - #define SECRET_TYPE_SERVICE (secret_service_get_type ()) #define SECRET_SERVICE(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), SECRET_TYPE_SERVICE, SecretService)) #define SECRET_SERVICE_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), SECRET_TYPE_SERVICE, SecretServiceClass)) diff --git a/libsecret/secret-types.h b/libsecret/secret-types.h index 708c53f..cbbd3b1 100644 --- a/libsecret/secret-types.h +++ b/libsecret/secret-types.h @@ -38,6 +38,13 @@ typedef enum { #define SECRET_COLLECTION_SESSION "session" +typedef enum { + SECRET_SEARCH_NONE = 0, + SECRET_SEARCH_ALL = 1 << 1, + SECRET_SEARCH_UNLOCK = 1 << 2, + SECRET_SEARCH_LOAD_SECRETS = 1 << 3, +} SecretSearchFlags; + G_END_DECLS #endif /* __G_SERVICE_H___ */ diff --git a/libsecret/test-password.c b/libsecret/test-password.c index cbfb561..01053eb 100644 --- a/libsecret/test-password.c +++ b/libsecret/test-password.c @@ -356,6 +356,90 @@ test_clear_no_name (Test *test, g_assert_true (ret); } +static void +free_attributes (gpointer data, + gpointer user_data) +{ + g_object_unref ((GObject *)data); +} + +static void +test_search_sync (Test *test, + gconstpointer used) +{ + GList *items; + GError *error = NULL; + + items = secret_password_search_sync (&MOCK_SCHEMA, SECRET_SEARCH_ALL, + NULL, &error, + "even", FALSE, + "string", "one", + "number", 1, + NULL); + + g_assert_no_error (error); + g_assert_cmpint (g_list_length (items), ==, 1); + + g_list_foreach (items, free_attributes, NULL); + g_list_free (items); +} + +static void +test_search_async (Test *test, + gconstpointer used) +{ + GAsyncResult *result = NULL; + GError *error = NULL; + GList *items; + + secret_password_search (&MOCK_SCHEMA, SECRET_SEARCH_ALL, + NULL, on_complete_get_result, &result, + "even", FALSE, + "string", "one", + "number", 1, + NULL); + g_assert (result == NULL); + + egg_test_wait (); + + items = secret_password_search_finish (result, &error); + g_assert_no_error (error); + g_object_unref (result); + + g_assert_cmpint (g_list_length (items), ==, 1); + + g_list_foreach (items, free_attributes, NULL); + g_list_free (items); +} + +static void +test_search_no_name (Test *test, + gconstpointer used) +{ + GError *error = NULL; + GList *items; + + /* should return null, because nothing with mock schema and 5 */ + items = secret_password_search_sync (&MOCK_SCHEMA, SECRET_SEARCH_ALL, + NULL, &error, + "number", 5, + NULL); + g_assert_no_error (error); + g_assert (items == NULL); + + /* should return an item, because we have a prime schema with 5, and flags not to match name */ + items = secret_password_search_sync (&NO_NAME_SCHEMA, SECRET_SEARCH_ALL, + NULL, &error, + "number", 5, + NULL); + + g_assert_no_error (error); + g_assert_cmpint (g_list_length (items), ==, 1); + + g_list_foreach (items, free_attributes, NULL); + g_list_free (items); +} + static void test_password_free_null (void) { @@ -380,6 +464,10 @@ main (int argc, char **argv) g_test_add ("/password/delete-async", Test, "mock-service-delete.py", setup, test_delete_async, teardown); g_test_add ("/password/clear-no-name", Test, "mock-service-delete.py", setup, test_clear_no_name, teardown); + g_test_add ("/password/search-sync", Test, "mock-service-normal.py", setup, test_search_sync, teardown); + g_test_add ("/password/search-async", Test, "mock-service-normal.py", setup, test_search_async, teardown); + g_test_add ("/password/search-no-name", Test, "mock-service-normal.py", setup, test_search_no_name, teardown); + g_test_add_func ("/password/free-null", test_password_free_null); return egg_tests_run_with_loop (); From bac85c00fc565d0c5e8519e910225a464949698a Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Thu, 20 Jun 2019 06:55:37 +0200 Subject: [PATCH 4/9] secret-password: Add lookup_binary functions This adds a set of functions that return a SecretValue instead of a text password when looking up a secret. This is useful if the stored password is not null-terminated. --- .../libsecret/libsecret-sections.txt | 3 + libsecret/secret-password.c | 125 ++++++++++++++++++ libsecret/secret-password.h | 63 +++++---- 3 files changed, 165 insertions(+), 26 deletions(-) diff --git a/docs/reference/libsecret/libsecret-sections.txt b/docs/reference/libsecret/libsecret-sections.txt index b561366..03cb96f 100644 --- a/docs/reference/libsecret/libsecret-sections.txt +++ b/docs/reference/libsecret/libsecret-sections.txt @@ -128,6 +128,9 @@ secret_password_lookup_sync secret_password_lookup_nonpageable_sync secret_password_lookupv_sync secret_password_lookupv_nonpageable_sync +secret_password_lookup_binary_finish +secret_password_lookup_binary_sync +secret_password_lookupv_binary_sync secret_password_clear secret_password_clearv secret_password_clear_finish diff --git a/libsecret/secret-password.c b/libsecret/secret-password.c index fc0ea0c..1ff0e86 100644 --- a/libsecret/secret-password.c +++ b/libsecret/secret-password.c @@ -407,6 +407,27 @@ secret_password_lookup_nonpageable_finish (GAsyncResult *result, return _secret_value_unref_to_password (value); } +/** + * secret_password_lookup_binary_finish: (skip) + * @result: the asynchronous result passed to the callback + * @error: location to place an error on failure + * + * Finish an asynchronous operation to lookup a password in the secret service. + * + * Returns: (transfer full): a newly allocated #SecretValue, which should be + * released with secret_value_unref(), or %NULL if no secret found + * + * Since: 0.19.0 + */ +SecretValue * +secret_password_lookup_binary_finish (GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + return secret_service_lookup_finish (NULL, result, error); +} + /** * secret_password_lookup_finish: * @result: the asynchronous result passed to the callback @@ -589,6 +610,110 @@ secret_password_lookupv_nonpageable_sync (const SecretSchema *schema, return password; } +/** + * secret_password_lookup_binary_sync: (skip) + * @schema: the schema for the attributes + * @cancellable: optional cancellation object + * @error: location to place an error on failure + * @...: the attribute keys and values, terminated with %NULL + * + * Lookup a password in the secret service. + * + * This is similar to secret_password_lookup_sync(), but returns a + * #SecretValue instead of a null-terminated password. + * + * This method may block indefinitely and should not be used in user interface + * threads. + * + * Returns: (transfer full): a newly allocated #SecretValue, which should be + * released with secret_value_unref(), or %NULL if no secret found + * + * Since: 0.19.0 + */ +SecretValue * +secret_password_lookup_binary_sync (const SecretSchema *schema, + GCancellable *cancellable, + GError **error, + ...) +{ + GHashTable *attributes; + SecretValue *value; + va_list va; + + g_return_val_if_fail (schema != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + va_start (va, error); + attributes = secret_attributes_buildv (schema, va); + va_end (va); + + /* Precondition failed, already warned */ + if (!attributes) + return NULL; + + value = secret_password_lookupv_binary_sync (schema, attributes, + cancellable, error); + + g_hash_table_unref (attributes); + + return value; +} + +/** + * secret_password_lookupv_binary_sync: (skip) + * @schema: the schema for attributes + * @attributes: (element-type utf8 utf8): the attribute keys and values + * @cancellable: optional cancellation object + * @error: location to place an error on failure + * + * Lookup a password in the secret service. + * + * This is similar to secret_password_lookupv_sync(), but returns a + * #SecretValue instead of a null-terminated password. + * + * This method may block indefinitely and should not be used in user interface + * threads. + * + * Returns: (transfer full): a newly allocated #SecretValue, which should be + * released with secret_value_unref(), or %NULL if no secret found + * + * Since: 0.19.0 + */ +SecretValue * +secret_password_lookupv_binary_sync (const SecretSchema *schema, + GHashTable *attributes, + GCancellable *cancellable, + GError **error) +{ + SecretSync *sync; + SecretValue *value; + + g_return_val_if_fail (schema != NULL, NULL); + g_return_val_if_fail (attributes != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* Warnings raised already */ + if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) + return FALSE; + + sync = _secret_sync_new (); + g_main_context_push_thread_default (sync->context); + + secret_password_lookupv (schema, attributes, cancellable, + _secret_sync_on_result, sync); + + g_main_loop_run (sync->loop); + + value = secret_password_lookup_binary_finish (sync->result, error); + + g_main_context_pop_thread_default (sync->context); + _secret_sync_free (sync); + + return value; +} + /** * secret_password_lookupv_sync: (rename-to secret_password_lookup_sync) * @schema: the schema for attributes diff --git a/libsecret/secret-password.h b/libsecret/secret-password.h index 725d11b..36cc18d 100644 --- a/libsecret/secret-password.h +++ b/libsecret/secret-password.h @@ -25,8 +25,9 @@ G_BEGIN_DECLS #include "secret-schema.h" #include "secret-types.h" +#include "secret-value.h" -void secret_password_store (const SecretSchema *schema, +void secret_password_store (const SecretSchema *schema, const gchar *collection, const gchar *label, const gchar *password, @@ -35,7 +36,7 @@ void secret_password_store (const SecretSchema *sche gpointer user_data, ...) G_GNUC_NULL_TERMINATED; -void secret_password_storev (const SecretSchema *schema, +void secret_password_storev (const SecretSchema *schema, GHashTable *attributes, const gchar *collection, const gchar *label, @@ -44,10 +45,10 @@ void secret_password_storev (const SecretSchema *sche GAsyncReadyCallback callback, gpointer user_data); -gboolean secret_password_store_finish (GAsyncResult *result, +gboolean secret_password_store_finish (GAsyncResult *result, GError **error); -gboolean secret_password_store_sync (const SecretSchema *schema, +gboolean secret_password_store_sync (const SecretSchema *schema, const gchar *collection, const gchar *label, const gchar *password, @@ -55,7 +56,7 @@ gboolean secret_password_store_sync (const SecretSchema *sche GError **error, ...) G_GNUC_NULL_TERMINATED; -gboolean secret_password_storev_sync (const SecretSchema *schema, +gboolean secret_password_storev_sync (const SecretSchema *schema, GHashTable *attributes, const gchar *collection, const gchar *label, @@ -63,101 +64,111 @@ gboolean secret_password_storev_sync (const SecretSchema *sche GCancellable *cancellable, GError **error); -void secret_password_lookup (const SecretSchema *schema, +void secret_password_lookup (const SecretSchema *schema, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, ...) G_GNUC_NULL_TERMINATED; -void secret_password_lookupv (const SecretSchema *schema, +void secret_password_lookupv (const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); -gchar * secret_password_lookup_finish (GAsyncResult *result, +gchar * secret_password_lookup_finish (GAsyncResult *result, GError **error); -gchar * secret_password_lookup_nonpageable_finish (GAsyncResult *result, - GError **error); +gchar * secret_password_lookup_nonpageable_finish (GAsyncResult *result, + GError **error); +SecretValue *secret_password_lookup_binary_finish (GAsyncResult *result, + GError **error); -gchar * secret_password_lookup_sync (const SecretSchema *schema, +gchar * secret_password_lookup_sync (const SecretSchema *schema, GCancellable *cancellable, GError **error, ...) G_GNUC_NULL_TERMINATED; -gchar * secret_password_lookup_nonpageable_sync (const SecretSchema *schema, +gchar * secret_password_lookup_nonpageable_sync (const SecretSchema *schema, GCancellable *cancellable, GError **error, ...); +SecretValue *secret_password_lookup_binary_sync (const SecretSchema *schema, + GCancellable *cancellable, + GError **error, + ...); -gchar * secret_password_lookupv_sync (const SecretSchema *schema, +gchar * secret_password_lookupv_sync (const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GError **error); -gchar * secret_password_lookupv_nonpageable_sync (const SecretSchema *schema, +gchar * secret_password_lookupv_nonpageable_sync (const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GError **error); +SecretValue *secret_password_lookupv_binary_sync (const SecretSchema *schema, + GHashTable *attributes, + GCancellable *cancellable, + GError **error); -void secret_password_clear (const SecretSchema *schema, +void secret_password_clear (const SecretSchema *schema, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, ...) G_GNUC_NULL_TERMINATED; -void secret_password_clearv (const SecretSchema *schema, +void secret_password_clearv (const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); -gboolean secret_password_clear_finish (GAsyncResult *result, +gboolean secret_password_clear_finish (GAsyncResult *result, GError **error); -gboolean secret_password_clear_sync (const SecretSchema* schema, +gboolean secret_password_clear_sync (const SecretSchema* schema, GCancellable *cancellable, GError **error, ...) G_GNUC_NULL_TERMINATED; -gboolean secret_password_clearv_sync (const SecretSchema *schema, +gboolean secret_password_clearv_sync (const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GError **error); -void secret_password_search (const SecretSchema *schema, +void secret_password_search (const SecretSchema *schema, SecretSearchFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, ...) G_GNUC_NULL_TERMINATED; -void secret_password_searchv (const SecretSchema *schema, +void secret_password_searchv (const SecretSchema *schema, GHashTable *attributes, SecretSearchFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); -GList * secret_password_search_sync (const SecretSchema *schema, +GList * secret_password_search_sync (const SecretSchema *schema, SecretSearchFlags flags, GCancellable *cancellable, GError **error, ...) G_GNUC_NULL_TERMINATED; -GList * secret_password_searchv_sync (const SecretSchema *schema, +GList * secret_password_searchv_sync (const SecretSchema *schema, GHashTable *attributes, SecretSearchFlags flags, GCancellable *cancellable, GError **error); -GList * secret_password_search_finish (GAsyncResult *result, +GList * secret_password_search_finish (GAsyncResult *result, GError **error); -void secret_password_free (gchar *password); +void secret_password_free (gchar *password); -void secret_password_wipe (gchar *password); +void secret_password_wipe (gchar *password); G_END_DECLS From 29c1460fd73c4ee7dc4bb9c7d30dcf5b525d0314 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Fri, 21 Jun 2019 06:54:51 +0200 Subject: [PATCH 5/9] secret-password: Add store_binary functions This adds a set of functions that takes a SecretValue instead of a text password when storing a secret. This is useful if the stored password is not null-terminated. --- .../libsecret/libsecret-sections.txt | 4 + libsecret/secret-password.c | 213 ++++++++++++++++++ libsecret/secret-password.h | 34 +++ 3 files changed, 251 insertions(+) diff --git a/docs/reference/libsecret/libsecret-sections.txt b/docs/reference/libsecret/libsecret-sections.txt index 03cb96f..d8f9509 100644 --- a/docs/reference/libsecret/libsecret-sections.txt +++ b/docs/reference/libsecret/libsecret-sections.txt @@ -120,6 +120,10 @@ secret_password_storev secret_password_store_finish secret_password_store_sync secret_password_storev_sync +secret_password_store_binary +secret_password_store_binary_sync +secret_password_storev_binary +secret_password_storev_binary_sync secret_password_lookup secret_password_lookupv secret_password_lookup_finish diff --git a/libsecret/secret-password.c b/libsecret/secret-password.c index 1ff0e86..a59d61e 100644 --- a/libsecret/secret-password.c +++ b/libsecret/secret-password.c @@ -156,6 +156,102 @@ secret_password_storev (const SecretSchema *schema, secret_value_unref (value); } +/** + * secret_password_store_binary: (skip) + * @schema: the schema for attributes + * @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 + * @user_data: data to be passed to the callback + * @...: the attribute keys and values, terminated with %NULL + * + * Store a password in the secret service. + * + * This is similar to secret_password_store(), but takes a + * #SecretValue as the argument instead of a null-terminated password. + * + * This method will return immediately and complete asynchronously. + * + * Since: 0.19.0 + */ +void +secret_password_store_binary (const SecretSchema *schema, + const gchar *collection, + const gchar *label, + SecretValue *value, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data, + ...) +{ + GHashTable *attributes; + va_list va; + + g_return_if_fail (schema != NULL); + g_return_if_fail (label != NULL); + g_return_if_fail (value != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + va_start (va, user_data); + attributes = secret_attributes_buildv (schema, va); + va_end (va); + + /* Precondition failed, already warned */ + if (!attributes) + return; + + secret_password_storev_binary (schema, attributes, collection, label, value, + cancellable, callback, user_data); + + g_hash_table_unref (attributes); +} + +/** + * secret_password_storev_binary: (rename-to secret_password_store_binary) + * @schema: the schema for attributes + * @attributes: (element-type utf8 utf8): 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 + * @user_data: data to be passed to the callback + * + * Store a password in the secret service. + * + * This is similar to secret_password_storev(), but takes a + * #SecretValue as the argument instead of a null-terminated password. + * + * This method will return immediately and complete asynchronously. + * + * Since: 0.19.0 + */ +void +secret_password_storev_binary (const SecretSchema *schema, + GHashTable *attributes, + const gchar *collection, + const gchar *label, + SecretValue *value, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_return_if_fail (schema != NULL); + g_return_if_fail (label != NULL); + g_return_if_fail (value != NULL); + g_return_if_fail (attributes != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + /* Warnings raised already */ + if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) + return; + + secret_service_store (NULL, schema, attributes, collection, + label, value, cancellable, callback, user_data); +} + /** * secret_password_store_finish: * @result: the asynchronous result passed to the callback @@ -301,6 +397,123 @@ secret_password_storev_sync (const SecretSchema *schema, return ret; } +/** + * secret_password_store_binary_sync: + * @schema: the schema for attributes + * @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 + * @error: location to place an error on failure + * @...: the attribute keys and values, terminated with %NULL + * + * Store a password in the secret service. + * + * This is similar to secret_password_store_sync(), but takes a + * #SecretValue as the argument instead of a null terminated password. + * + * This method may block indefinitely and should not be used in user interface + * threads. + * + * Returns: whether the storage was successful or not + * + * Since: 0.19.0 + */ +gboolean +secret_password_store_binary_sync (const SecretSchema *schema, + const gchar *collection, + const gchar *label, + SecretValue *value, + GCancellable *cancellable, + GError **error, + ...) +{ + GHashTable *attributes; + va_list va; + gboolean ret; + + g_return_val_if_fail (schema != NULL, FALSE); + g_return_val_if_fail (label != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + va_start (va, error); + attributes = secret_attributes_buildv (schema, va); + va_end (va); + + /* Precondition failed, already warned */ + if (!attributes) + return FALSE; + + ret = secret_password_storev_binary_sync (schema, attributes, collection, + label, value, cancellable, error); + + g_hash_table_unref (attributes); + return ret; +} + +/** + * secret_password_storev_binary_sync: (rename-to secret_password_store_binary_sync) + * @schema: the schema for attributes + * @attributes: (element-type utf8 utf8): 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 + * @error: location to place an error on failure + * + * Store a password in the secret service. + * + * This is similar to secret_password_storev_sync(), but takes a + * #SecretValue as the argument instead of a null-terminated passwords. + * + * This method may block indefinitely and should not be used in user interface + * threads. + * + * Returns: whether the storage was successful or not + * + * Since: 0.19.0 + */ +gboolean +secret_password_storev_binary_sync (const SecretSchema *schema, + GHashTable *attributes, + const gchar *collection, + const gchar *label, + SecretValue *value, + GCancellable *cancellable, + GError **error) +{ + SecretSync *sync; + gboolean ret; + + g_return_val_if_fail (schema != NULL, FALSE); + g_return_val_if_fail (label != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (attributes != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* Warnings raised already */ + if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) + return FALSE; + + sync = _secret_sync_new (); + g_main_context_push_thread_default (sync->context); + + secret_password_storev_binary (schema, attributes, collection, label, value, + cancellable, _secret_sync_on_result, sync); + + g_main_loop_run (sync->loop); + + ret = secret_password_store_finish (sync->result, error); + + g_main_context_pop_thread_default (sync->context); + _secret_sync_free (sync); + + return ret; +} + /** * secret_password_lookup: (skip) * @schema: the schema for the attributes diff --git a/libsecret/secret-password.h b/libsecret/secret-password.h index 36cc18d..0719317 100644 --- a/libsecret/secret-password.h +++ b/libsecret/secret-password.h @@ -45,6 +45,24 @@ void secret_password_storev (const SecretSchema *sche GAsyncReadyCallback callback, gpointer user_data); +void secret_password_store_binary (const SecretSchema *schema, + const gchar *collection, + const gchar *label, + SecretValue *value, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data, + ...); + +void secret_password_storev_binary (const SecretSchema *schema, + GHashTable *attributes, + const gchar *collection, + const gchar *label, + SecretValue *value, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean secret_password_store_finish (GAsyncResult *result, GError **error); @@ -64,6 +82,22 @@ gboolean secret_password_storev_sync (const SecretSchema *sche GCancellable *cancellable, GError **error); +gboolean secret_password_store_binary_sync (const SecretSchema *schema, + const gchar *collection, + const gchar *label, + SecretValue *value, + GCancellable *cancellable, + GError **error, + ...); + +gboolean secret_password_storev_binary_sync (const SecretSchema *schema, + GHashTable *attributes, + const gchar *collection, + const gchar *label, + SecretValue *value, + GCancellable *cancellable, + GError **error); + void secret_password_lookup (const SecretSchema *schema, GCancellable *cancellable, GAsyncReadyCallback callback, From 2ae6ec89f43f076d622658275bd24c57996c18c5 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Sat, 29 Jun 2019 09:55:01 +0200 Subject: [PATCH 6/9] tests: Add tests for binary variant of secret_{lookup,store} --- libsecret/test-password.c | 73 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/libsecret/test-password.c b/libsecret/test-password.c index 01053eb..f20a31b 100644 --- a/libsecret/test-password.c +++ b/libsecret/test-password.c @@ -440,6 +440,76 @@ test_search_no_name (Test *test, g_list_free (items); } +static void +test_binary_sync (Test *test, + gconstpointer used) +{ + const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; + GError *error = NULL; + SecretValue *value; + gboolean ret; + + value = secret_value_new ("the password", -1, "text/plain"); + ret = secret_password_store_binary_sync (&MOCK_SCHEMA, collection_path, + "Label here", value, NULL, &error, + "even", TRUE, + "string", "twelve", + "number", 12, + NULL); + + g_assert_no_error (error); + g_assert_true (ret); + secret_value_unref (value); + + value = secret_password_lookup_binary_sync (&MOCK_SCHEMA, NULL, &error, + "string", "twelve", + NULL); + + g_assert_no_error (error); + g_assert_cmpstr (secret_value_get_text (value), ==, "the password"); + + secret_value_unref (value); +} + +static void +test_binary_async (Test *test, + gconstpointer used) +{ + const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; + GAsyncResult *result = NULL; + GError *error = NULL; + SecretValue *value; + gboolean ret; + + value = secret_value_new ("the password", -1, "text/plain"); + secret_password_store_binary (&MOCK_SCHEMA, collection_path, "Label here", + value, NULL, on_complete_get_result, &result, + "even", TRUE, + "string", "twelve", + "number", 12, + NULL); + g_assert_null (result); + secret_value_unref (value); + + egg_test_wait (); + + ret = secret_password_store_finish (result, &error); + g_assert_no_error (error); + g_assert_true (ret); + g_object_unref (result); + + value = secret_password_lookup_binary_sync (&MOCK_SCHEMA, NULL, &error, + "string", "twelve", + NULL); + + g_assert_no_error (error); + g_assert_nonnull (value); + + g_assert_cmpstr (secret_value_get_text (value), ==, "the password"); + + secret_value_unref (value); +} + static void test_password_free_null (void) { @@ -468,6 +538,9 @@ main (int argc, char **argv) g_test_add ("/password/search-async", Test, "mock-service-normal.py", setup, test_search_async, teardown); g_test_add ("/password/search-no-name", Test, "mock-service-normal.py", setup, test_search_no_name, teardown); + g_test_add ("/password/binary-sync", Test, "mock-service-normal.py", setup, test_binary_sync, teardown); + g_test_add ("/password/binary-async", Test, "mock-service-normal.py", setup, test_binary_async, teardown); + g_test_add_func ("/password/free-null", test_password_free_null); return egg_tests_run_with_loop (); From a5db34dcd5991796eb5c370ada5b70b386df9d80 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Thu, 20 Jun 2019 06:55:56 +0200 Subject: [PATCH 7/9] secret-value: Add secret_value_unref_to_password This adds the secret_value_unref_to_password function that unreferences and returns the stored secret in non-pageable memory. This is supposed to be used with secret_password_lookup_binary* functions. --- .../libsecret/libsecret-sections.txt | 1 + libsecret/secret-value.c | 64 +++++++++++++------ libsecret/secret-value.h | 3 + 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/docs/reference/libsecret/libsecret-sections.txt b/docs/reference/libsecret/libsecret-sections.txt index d8f9509..f811b9d 100644 --- a/docs/reference/libsecret/libsecret-sections.txt +++ b/docs/reference/libsecret/libsecret-sections.txt @@ -333,6 +333,7 @@ secret_value_get_text secret_value_get_content_type secret_value_ref secret_value_unref +secret_value_unref_to_password SECRET_TYPE_VALUE secret_value_get_type diff --git a/libsecret/secret-value.c b/libsecret/secret-value.c index ca891cb..63464cd 100644 --- a/libsecret/secret-value.c +++ b/libsecret/secret-value.c @@ -256,36 +256,64 @@ is_password_value (SecretValue *value) return FALSE; } +/** + * secret_value_unref_to_password: + * @value: the value + * @length: the length of the secret + * + * Unreference a #SecretValue and steal the secret data in + * #SecretValue as nonpageable memory. + * + * Returns: (transfer full): a new password string stored in nonpageable memory + * which must be freed with secret_password_free() when done + * + * Since: 0.19.0 + */ gchar * -_secret_value_unref_to_password (SecretValue *value) +secret_value_unref_to_password (SecretValue *value, + gsize *length) { SecretValue *val = value; gchar *result; g_return_val_if_fail (value != NULL, NULL); + if (g_atomic_int_dec_and_test (&val->refs)) { + if (val->destroy == egg_secure_free) { + result = val->secret; + if (length) + *length = val->length; + + } else { + result = egg_secure_strndup (val->secret, val->length); + if (val->destroy) + (val->destroy) (val->secret); + if (length) + *length = val->length; + } + g_free (val->content_type); + g_slice_free (SecretValue, val); + + } else { + result = egg_secure_strndup (val->secret, val->length); + if (length) + *length = val->length; + } + + return result; +} + +gchar * +_secret_value_unref_to_password (SecretValue *value) +{ + g_return_val_if_fail (value != NULL, NULL); + if (!is_password_value (value)) { secret_value_unref (value); return NULL; } - if (g_atomic_int_dec_and_test (&val->refs)) { - if (val->destroy == egg_secure_free) { - result = val->secret; - - } else { - result = egg_secure_strndup (val->secret, val->length); - if (val->destroy) - (val->destroy) (val->secret); - } - g_free (val->content_type); - g_slice_free (SecretValue, val); - - } else { - result = egg_secure_strndup (val->secret, val->length); - } - - return result; + return secret_value_unref_to_password (value, NULL); } gchar * diff --git a/libsecret/secret-value.h b/libsecret/secret-value.h index 43b0e09..7699c08 100644 --- a/libsecret/secret-value.h +++ b/libsecret/secret-value.h @@ -51,6 +51,9 @@ SecretValue * secret_value_ref (SecretValue *value); void secret_value_unref (gpointer value); +gchar * secret_value_unref_to_password (SecretValue *value, + gsize *length); + G_DEFINE_AUTOPTR_CLEANUP_FUNC (SecretValue, secret_value_unref) G_END_DECLS From e3963efdee7e344f3cee634995e64c49760d3356 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Mon, 8 Jul 2019 10:53:41 +0200 Subject: [PATCH 8/9] secret-password: Mark @schema argument nullable for *v functions Given these functions take a hash table built from valid attributes, there is no need to re-validate. This is also consistent with the secret_service API. --- libsecret/secret-password.c | 60 +++++++++++++++---------------------- 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/libsecret/secret-password.c b/libsecret/secret-password.c index a59d61e..632ed2d 100644 --- a/libsecret/secret-password.c +++ b/libsecret/secret-password.c @@ -104,7 +104,7 @@ secret_password_store (const SecretSchema *schema, /** * secret_password_storev: (rename-to secret_password_store) - * @schema: the schema for attributes + * @schema: (nullable): the schema for attributes * @attributes: (element-type utf8 utf8): 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 @@ -138,14 +138,13 @@ secret_password_storev (const SecretSchema *schema, { SecretValue *value; - g_return_if_fail (schema != NULL); g_return_if_fail (label != NULL); g_return_if_fail (password != NULL); g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); /* Warnings raised already */ - if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) + if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) return; value = secret_value_new (password, -1, "text/plain"); @@ -210,7 +209,7 @@ secret_password_store_binary (const SecretSchema *schema, /** * secret_password_storev_binary: (rename-to secret_password_store_binary) - * @schema: the schema for attributes + * @schema: (nullable): the schema for attributes * @attributes: (element-type utf8 utf8): 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 @@ -238,14 +237,13 @@ secret_password_storev_binary (const SecretSchema *schema, GAsyncReadyCallback callback, gpointer user_data) { - g_return_if_fail (schema != NULL); g_return_if_fail (label != NULL); g_return_if_fail (value != NULL); g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); /* Warnings raised already */ - if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) + if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) return; secret_service_store (NULL, schema, attributes, collection, @@ -334,7 +332,7 @@ secret_password_store_sync (const SecretSchema *schema, /** * secret_password_storev_sync: (rename-to secret_password_store_sync) - * @schema: the schema for attributes + * @schema: (nullable): the schema for attributes * @attributes: (element-type utf8 utf8): 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 @@ -370,7 +368,6 @@ secret_password_storev_sync (const SecretSchema *schema, SecretSync *sync; gboolean ret; - g_return_val_if_fail (schema != NULL, FALSE); g_return_val_if_fail (label != NULL, FALSE); g_return_val_if_fail (password != NULL, FALSE); g_return_val_if_fail (attributes != NULL, FALSE); @@ -378,7 +375,7 @@ secret_password_storev_sync (const SecretSchema *schema, g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* Warnings raised already */ - if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) + if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) return FALSE; sync = _secret_sync_new (); @@ -455,7 +452,7 @@ secret_password_store_binary_sync (const SecretSchema *schema, /** * secret_password_storev_binary_sync: (rename-to secret_password_store_binary_sync) - * @schema: the schema for attributes + * @schema: (nullable): the schema for attributes * @attributes: (element-type utf8 utf8): 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 @@ -487,7 +484,6 @@ secret_password_storev_binary_sync (const SecretSchema *schema, SecretSync *sync; gboolean ret; - g_return_val_if_fail (schema != NULL, FALSE); g_return_val_if_fail (label != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); g_return_val_if_fail (attributes != NULL, FALSE); @@ -495,7 +491,7 @@ secret_password_storev_binary_sync (const SecretSchema *schema, g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* Warnings raised already */ - if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) + if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) return FALSE; sync = _secret_sync_new (); @@ -562,7 +558,7 @@ secret_password_lookup (const SecretSchema *schema, /** * secret_password_lookupv: (rename-to secret_password_lookup) - * @schema: the schema for attributes + * @schema: (nullable): the schema for attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @cancellable: optional cancellation object * @callback: called when the operation completes @@ -583,12 +579,11 @@ secret_password_lookupv (const SecretSchema *schema, GAsyncReadyCallback callback, gpointer user_data) { - g_return_if_fail (schema != NULL); g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); /* Warnings raised already */ - if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) + if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return; secret_service_lookup (NULL, schema, attributes, @@ -772,7 +767,7 @@ secret_password_lookup_nonpageable_sync (const SecretSchema *schema, /** * secret_password_lookupv_nonpageable_sync: (skip) - * @schema: the schema for attributes + * @schema: (nullable): the schema for attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @cancellable: optional cancellation object * @error: location to place an error on failure @@ -798,13 +793,12 @@ secret_password_lookupv_nonpageable_sync (const SecretSchema *schema, SecretSync *sync; gchar *password; - g_return_val_if_fail (schema != NULL, NULL); g_return_val_if_fail (attributes != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* Warnings raised already */ - if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) + if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return FALSE; sync = _secret_sync_new (); @@ -875,7 +869,7 @@ secret_password_lookup_binary_sync (const SecretSchema *schema, /** * secret_password_lookupv_binary_sync: (skip) - * @schema: the schema for attributes + * @schema: (nullable): the schema for attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @cancellable: optional cancellation object * @error: location to place an error on failure @@ -902,13 +896,12 @@ secret_password_lookupv_binary_sync (const SecretSchema *schema, SecretSync *sync; SecretValue *value; - g_return_val_if_fail (schema != NULL, NULL); g_return_val_if_fail (attributes != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* Warnings raised already */ - if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) + if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return FALSE; sync = _secret_sync_new (); @@ -929,7 +922,7 @@ secret_password_lookupv_binary_sync (const SecretSchema *schema, /** * secret_password_lookupv_sync: (rename-to secret_password_lookup_sync) - * @schema: the schema for attributes + * @schema: (nullable): the schema for attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @cancellable: optional cancellation object * @error: location to place an error on failure @@ -955,13 +948,12 @@ secret_password_lookupv_sync (const SecretSchema *schema, SecretSync *sync; gchar *string; - g_return_val_if_fail (schema != NULL, NULL); g_return_val_if_fail (attributes != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* Warnings raised already */ - if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) + if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return FALSE; sync = _secret_sync_new (); @@ -1029,7 +1021,7 @@ secret_password_clear (const SecretSchema *schema, /** * secret_password_clearv: (rename-to secret_password_clear) - * @schema: the schema for the attributes + * @schema: (nullable): the schema for the attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @cancellable: optional cancellation object * @callback: called when the operation completes @@ -1050,12 +1042,11 @@ secret_password_clearv (const SecretSchema *schema, GAsyncReadyCallback callback, gpointer user_data) { - g_return_if_fail (schema != NULL); g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); /* Warnings raised already */ - if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) + if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return; secret_service_clear (NULL, schema, attributes, @@ -1133,7 +1124,7 @@ secret_password_clear_sync (const SecretSchema* schema, /** * secret_password_clearv_sync: (rename-to secret_password_clear_sync) - * @schema: the schema for the attributes + * @schema: (nullable): the schema for the attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @cancellable: optional cancellation object * @error: location to place an error on failure @@ -1158,13 +1149,12 @@ secret_password_clearv_sync (const SecretSchema *schema, SecretSync *sync; gboolean result; - g_return_val_if_fail (schema != NULL, FALSE); g_return_val_if_fail (attributes != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* Warnings raised already */ - if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) + if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return FALSE; sync = _secret_sync_new (); @@ -1233,7 +1223,7 @@ secret_password_search (const SecretSchema *schema, /** * secret_password_searchv: (rename-to secret_password_search) - * @schema: the schema for attributes + * @schema: (nullable): the schema for attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @flags: search option flags * @cancellable: optional cancellation object @@ -1256,12 +1246,11 @@ secret_password_searchv (const SecretSchema *schema, GAsyncReadyCallback callback, gpointer user_data) { - g_return_if_fail (schema != NULL); g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); /* Warnings raised already */ - if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) + if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return; secret_service_search (NULL, schema, attributes, flags, @@ -1347,7 +1336,7 @@ secret_password_search_sync (const SecretSchema *schema, /** * secret_password_searchv_sync: (rename-to secret_password_search_sync) - * @schema: the schema for attributes + * @schema: (nullable): the schema for attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @flags: search option flags * @cancellable: optional cancellation object @@ -1377,13 +1366,12 @@ secret_password_searchv_sync (const SecretSchema *schema, SecretSync *sync; GList *items; - g_return_val_if_fail (schema != NULL, NULL); g_return_val_if_fail (attributes != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* Warnings raised already */ - if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) + if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return NULL; sync = _secret_sync_new (); From 6886aebb0457d752f348a4cedc5a11ce109544ee Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Thu, 20 Jun 2019 11:01:18 +0200 Subject: [PATCH 9/9] secret-tool: Switch to using the simple API --- tool/secret-tool.c | 138 ++++++++++++++++++++++++--------------------- 1 file changed, 74 insertions(+), 64 deletions(-) diff --git a/tool/secret-tool.c b/tool/secret-tool.c index 524a364..9f16257 100644 --- a/tool/secret-tool.c +++ b/tool/secret-tool.c @@ -16,7 +16,7 @@ #include "libsecret/secret-item.h" #include "libsecret/secret-password.h" -#include "libsecret/secret-service.h" +#include "libsecret/secret-retrievable.h" #include "libsecret/secret-value.h" #include @@ -122,8 +122,8 @@ secret_tool_action_clear (int argc, { GError *error = NULL; GOptionContext *context; - SecretService *service; GHashTable *attributes; + gboolean ret; context = g_option_context_new ("attribute value ..."); g_option_context_add_main_entries (context, CLEAR_OPTIONS, GETTEXT_PACKAGE); @@ -137,14 +137,11 @@ secret_tool_action_clear (int argc, attributes = attributes_from_arguments (attribute_args); g_strfreev (attribute_args); - service = secret_service_get_sync (SECRET_SERVICE_NONE, NULL, &error); - if (error == NULL) - secret_service_clear_sync (service, NULL, attributes, NULL, &error); + ret = secret_password_clearv_sync (NULL, attributes, NULL, &error); - g_object_unref (service); g_hash_table_unref (attributes); - if (error != NULL) { + if (!ret) { g_printerr ("%s: %s\n", g_get_prgname (), error->message); return 1; } @@ -197,7 +194,6 @@ secret_tool_action_lookup (int argc, { GError *error = NULL; GOptionContext *context; - SecretService *service; GHashTable *attributes; SecretValue *value = NULL; @@ -213,11 +209,8 @@ secret_tool_action_lookup (int argc, attributes = attributes_from_arguments (attribute_args); g_strfreev (attribute_args); - service = secret_service_get_sync (SECRET_SERVICE_NONE, NULL, &error); - if (error == NULL) - value = secret_service_lookup_sync (service, NULL, attributes, NULL, &error); + value = secret_password_lookupv_binary_sync (NULL, attributes, NULL, &error); - g_object_unref (service); g_hash_table_unref (attributes); if (error != NULL) { @@ -285,10 +278,10 @@ secret_tool_action_store (int argc, { GError *error = NULL; GOptionContext *context; - SecretService *service; GHashTable *attributes; SecretValue *value; gchar *collection = NULL; + gboolean ret; context = g_option_context_new ("attribute value ..."); g_option_context_add_main_entries (context, STORE_OPTIONS, GETTEXT_PACKAGE); @@ -315,24 +308,20 @@ secret_tool_action_store (int argc, collection = g_strconcat (SECRET_ALIAS_PREFIX, store_collection, NULL); } - service = secret_service_get_sync (SECRET_SERVICE_NONE, NULL, &error); - if (error == NULL) { - if (isatty (0)) - value = read_password_tty (); - else - value = read_password_stdin (); + if (isatty (0)) + value = read_password_tty (); + else + value = read_password_stdin (); - secret_service_store_sync (service, NULL, attributes, collection, store_label, value, NULL, &error); - secret_value_unref (value); - } + ret = secret_password_storev_binary_sync (NULL, attributes, collection, store_label, value, NULL, &error); + secret_value_unref (value); - g_object_unref (service); g_hash_table_unref (attributes); g_free (store_label); g_free (store_collection); g_free (collection); - if (error != NULL) { + if (!ret) { g_printerr ("%s: %s\n", g_get_prgname (), error->message); return 1; } @@ -360,58 +349,76 @@ print_item_when (const char *field, } static void -print_item_details (SecretItem *item) +on_retrieve_secret (GObject *source_object, + GAsyncResult *res, + gpointer user_data) { + SecretRetrievable *item = SECRET_RETRIEVABLE (source_object); + GMainLoop *loop = user_data; SecretValue *secret; GHashTableIter iter; GHashTable *attributes; - gchar *value, *key; + const gchar *value, *key; guint64 when; + gchar *label; const gchar *part; const gchar *path; + GError *error; - path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (item)); - g_return_if_fail (path != NULL); + error = NULL; + secret = secret_retrievable_retrieve_secret_finish (item, res, &error); + if (!secret) { + g_printerr ("%s: %s\n", g_get_prgname (), error->message); + g_clear_error (&error); + } - /* The item identifier */ - part = strrchr (path, '/'); - if (part == NULL) - part = path; - g_print ("[%s]\n", path); + if (G_IS_DBUS_PROXY (item)) { + path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (item)); + g_return_if_fail (path != NULL); + + /* The item identifier */ + part = strrchr (path, '/'); + if (part == NULL) + part = path; + g_print ("[%s]\n", path); + } else { + g_print ("[no path]\n"); + } /* The label */ - value = secret_item_get_label (item); - g_print ("label = %s\n", value); - g_free (value); + label = secret_retrievable_get_label (item); + g_print ("label = %s\n", label); + g_free (label); - /* The secret value */ - secret = secret_item_get_secret (item); - g_print ("secret = "); - if (secret != NULL) { - write_password_data (secret); - secret_value_unref (secret); + if (secret) { + /* The secret value */ + g_print ("secret = "); + if (secret != NULL) { + write_password_data (secret); + secret_value_unref (secret); + } + g_print ("\n"); } - g_print ("\n"); /* The dates */ - when = secret_item_get_created (item); + when = secret_retrievable_get_created (item); print_item_when ("created", when); - when = secret_item_get_modified (item); + when = secret_retrievable_get_modified (item); print_item_when ("modified", when); - /* The schema */ - value = secret_item_get_schema_name (item); - g_print ("schema = %s\n", value); - g_free (value); - /* The attributes */ - attributes = secret_item_get_attributes (item); + attributes = secret_retrievable_get_attributes (item); + value = g_hash_table_lookup (attributes, "xdg:schema"); + if (value) + g_print ("schema = %s\n", value); + g_hash_table_iter_init (&iter, attributes); while (g_hash_table_iter_next (&iter, (void **)&key, (void **)&value)) { if (strcmp (key, "xdg:schema") != 0) g_printerr ("attribute.%s = %s\n", key, value); } g_hash_table_unref (attributes); + g_main_loop_quit (loop); } static int @@ -420,7 +427,6 @@ secret_tool_action_search (int argc, { GError *error = NULL; GOptionContext *context; - SecretService *service; GHashTable *attributes; SecretSearchFlags flags; gboolean flag_all = FALSE; @@ -450,21 +456,25 @@ secret_tool_action_search (int argc, attributes = attributes_from_arguments (attribute_args); g_strfreev (attribute_args); - service = secret_service_get_sync (SECRET_SERVICE_NONE, NULL, &error); + flags = SECRET_SEARCH_LOAD_SECRETS; + if (flag_all) + flags |= SECRET_SEARCH_ALL; + if (flag_unlock) + flags |= SECRET_SEARCH_UNLOCK; + items = secret_password_searchv_sync (NULL, attributes, flags, NULL, &error); if (error == NULL) { - flags = SECRET_SEARCH_LOAD_SECRETS; - if (flag_all) - flags |= SECRET_SEARCH_ALL; - if (flag_unlock) - flags |= SECRET_SEARCH_UNLOCK; - items = secret_service_search_sync (service, NULL, attributes, flags, NULL, &error); - if (error == NULL) { - for (l = items; l != NULL; l = g_list_next (l)) - print_item_details (l->data); - g_list_free_full (items, g_object_unref); + GMainLoop *loop = g_main_loop_new (NULL, FALSE); + + for (l = items; l != NULL; l = g_list_next (l)) { + SecretRetrievable *retrievable = SECRET_RETRIEVABLE (l->data); + secret_retrievable_retrieve_secret (retrievable, + NULL, + on_retrieve_secret, + loop); + g_main_loop_run (loop); } - g_object_unref (service); + g_list_free_full (items, g_object_unref); } g_hash_table_unref (attributes);