1 /* libsecret - GLib wrapper for Secret Service
3 * Copyright 2011 Collabora Ltd.
4 * Copyright 2012 Red Hat Inc.
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published
8 * by the Free Software Foundation; either version 2.1 of the licence or (at
9 * your option) any later version.
11 * See the included COPYING file for more information.
13 * Author: Stef Walter <stefw@gnome.org>
18 #include "secret-collection.h"
19 #include "secret-dbus-generated.h"
20 #include "secret-enum-types.h"
21 #include "secret-item.h"
22 #include "secret-paths.h"
23 #include "secret-private.h"
24 #include "secret-service.h"
25 #include "secret-types.h"
26 #include "secret-value.h"
28 #include "egg/egg-secure-memory.h"
31 * SECTION:secret-service
32 * @title: SecretService
33 * @short_description: the Secret Service
35 * A #SecretService object represents the Secret Service implementation which
36 * runs as a D-Bus service.
38 * Normally a single #SecretService object can be shared between multiple
39 * callers. The secret_service_get() method is used to access this #SecretService
40 * object. If a new independent #SecretService object is required, use
41 * secret_service_new().
43 * In order to securely transfer secrets to the Sercret Service, an session
44 * is established. This session can be established while initializing a
45 * #SecretService object by passing the %SECRET_SERVICE_OPEN_SESSION flag
46 * to the secret_service_get() or secret_service_new() functions. In order to
47 * establish a session on an already existing #SecretService, use the
48 * secret_service_ensure_session() function.
50 * To search for items, use the secret_service_search() method.
52 * Multiple collections can exist in the Secret Service, each of which contains
53 * secret items. In order to instantiate #SecretCollection objects which
54 * represent those collections while initializing a #SecretService then pass
55 * the %SECRET_SERVICE_LOAD_COLLECTIONS flag to the secret_service_get() or
56 * secret_service_new() functions. In order to establish a session on an already
57 * existing #SecretService, use the secret_service_load_collections() function.
58 * To access the list of collections use secret_service_get_collections().
60 * Certain actions on the Secret Service require user prompting to complete,
61 * such as creating a collection, or unlocking a collection. When such a prompt
62 * is necessary, then a #SecretPrompt object is created by this library, and
63 * passed to the secret_service_prompt() method. In this way it is handled
66 * In order to customize prompt handling, override the <literal>prompt_async</literal>
67 * and <literal>prompt_finish</literal> virtual methods of the #SecretService class.
75 * A proxy object representing the Secret Service.
80 * @parent_class: the parent class
81 * @collection_gtype: the #GType of the #SecretCollection objects instantiated
82 * by the #SecretService proxy
83 * @item_gtype: the #GType of the #SecretItem objects instantiated by the
84 * #SecretService proxy
85 * @prompt_async: called to perform asynchronous prompting when necessary
86 * @prompt_finish: called to complete an asynchronous prompt operation
87 * @prompt_sync: called to perform synchronous prompting when necessary
89 * The class for #SecretService.
94 * @SECRET_SERVICE_NONE: no flags for initializing the #SecretService
95 * @SECRET_SERVICE_OPEN_SESSION: establish a session for transfer of secrets
96 * while initializing the #SecretService
97 * @SECRET_SERVICE_LOAD_COLLECTIONS: load collections while initializing the
100 * Flags which determine which parts of the #SecretService proxy are initialized
101 * during a secret_service_get() or secret_service_new() operation.
104 EGG_SECURE_GLIB_DEFINITIONS ();
106 GQuark _secret_error_quark = 0;
107 static const gchar *default_bus_name = SECRET_SERVICE_BUS_NAME;
115 struct _SecretServicePrivate {
116 /* No change between construct and finalize */
117 GCancellable *cancellable;
118 SecretServiceFlags init_flags;
120 /* Locked by mutex */
123 GHashTable *collections;
126 G_LOCK_DEFINE (service_instance);
127 static gpointer service_instance = NULL;
128 static guint service_watch = 0;
130 static GInitableIface *secret_service_initable_parent_iface = NULL;
132 static GAsyncInitableIface *secret_service_async_initable_parent_iface = NULL;
134 static void secret_service_initable_iface (GInitableIface *iface);
136 static void secret_service_async_initable_iface (GAsyncInitableIface *iface);
138 G_DEFINE_TYPE_WITH_CODE (SecretService, secret_service, G_TYPE_DBUS_PROXY,
139 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, secret_service_initable_iface);
140 G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, secret_service_async_initable_iface);
143 static SecretService *
144 service_get_instance (void)
146 SecretService *instance = NULL;
148 G_LOCK (service_instance);
149 if (service_instance != NULL)
150 instance = g_object_ref (service_instance);
151 G_UNLOCK (service_instance);
157 service_uncache_instance (SecretService *which)
159 SecretService *instance = NULL;
161 gboolean matched = FALSE;
163 G_LOCK (service_instance);
164 if (which == NULL || service_instance == which) {
165 instance = service_instance;
166 service_instance = NULL;
167 watch = service_watch;
171 G_UNLOCK (service_instance);
173 if (instance != NULL)
174 g_object_unref (instance);
176 g_bus_unwatch_name (watch);
182 on_service_instance_vanished (GDBusConnection *connection,
186 if (!service_uncache_instance (user_data)) {
187 g_warning ("Global default SecretService instance out of sync "
188 "with the watch for its DBus name");
193 service_cache_instance (SecretService *instance)
198 g_object_ref (instance);
199 proxy = G_DBUS_PROXY (instance);
200 watch = g_bus_watch_name_on_connection (g_dbus_proxy_get_connection (proxy),
201 g_dbus_proxy_get_name (proxy),
202 G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
203 NULL, on_service_instance_vanished,
206 G_LOCK (service_instance);
207 if (service_instance == NULL) {
208 service_instance = instance;
210 service_watch = watch;
213 G_UNLOCK (service_instance);
215 if (instance != NULL)
216 g_object_unref (instance);
218 g_bus_unwatch_name (watch);
222 secret_service_init (SecretService *self)
224 self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, SECRET_TYPE_SERVICE,
225 SecretServicePrivate);
227 g_mutex_init (&self->pv->mutex);
228 self->pv->cancellable = g_cancellable_new ();
232 secret_service_get_property (GObject *obj,
237 SecretService *self = SECRET_SERVICE (obj);
241 g_value_set_flags (value, secret_service_get_flags (self));
243 case PROP_COLLECTIONS:
244 g_value_take_boxed (value, secret_service_get_collections (self));
247 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
253 secret_service_set_property (GObject *obj,
258 SecretService *self = SECRET_SERVICE (obj);
262 self->pv->init_flags = g_value_get_flags (value);
265 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
271 secret_service_dispose (GObject *obj)
273 SecretService *self = SECRET_SERVICE (obj);
275 g_cancellable_cancel (self->pv->cancellable);
277 G_OBJECT_CLASS (secret_service_parent_class)->dispose (obj);
281 secret_service_finalize (GObject *obj)
283 SecretService *self = SECRET_SERVICE (obj);
285 _secret_session_free (self->pv->session);
286 if (self->pv->collections)
287 g_hash_table_destroy (self->pv->collections);
288 g_clear_object (&self->pv->cancellable);
289 g_mutex_clear (&self->pv->mutex);
291 G_OBJECT_CLASS (secret_service_parent_class)->finalize (obj);
295 secret_service_real_prompt_sync (SecretService *self,
296 SecretPrompt *prompt,
297 GCancellable *cancellable,
298 const GVariantType *return_type,
301 return secret_prompt_perform_sync (prompt, 0, cancellable, return_type, error);
305 on_real_prompt_completed (GObject *source,
306 GAsyncResult *result,
309 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
310 GError *error = NULL;
313 retval = secret_prompt_perform_finish (SECRET_PROMPT (source), result, NULL, &error);
315 g_simple_async_result_set_op_res_gpointer (res, retval, (GDestroyNotify)g_variant_unref);
317 g_simple_async_result_take_error (res, error);
318 g_simple_async_result_complete (res);
319 g_object_unref (res);
323 secret_service_real_prompt_async (SecretService *self,
324 SecretPrompt *prompt,
325 GCancellable *cancellable,
326 GAsyncReadyCallback callback,
329 GSimpleAsyncResult *res;
331 res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
332 secret_service_real_prompt_async);
334 secret_prompt_perform (prompt, 0, cancellable,
335 on_real_prompt_completed,
338 g_object_unref (res);
342 secret_service_real_prompt_finish (SecretService *self,
343 GAsyncResult *result,
344 const GVariantType *return_type,
347 GSimpleAsyncResult *res;
351 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
352 secret_service_real_prompt_async), NULL);
354 res = G_SIMPLE_ASYNC_RESULT (result);
355 if (g_simple_async_result_propagate_error (res, error))
358 retval = g_simple_async_result_get_op_res_gpointer (res);
362 if (return_type != NULL && !g_variant_is_of_type (retval, return_type)) {
363 string = g_variant_type_dup_string (return_type);
364 g_warning ("received unexpected result type %s from prompt's Completed signal instead of expected %s",
365 g_variant_get_type_string (retval), string);
370 return g_variant_ref (retval);
374 handle_property_changed (SecretService *self,
375 const gchar *property_name,
380 g_variant_ref_sink (value);
382 if (g_str_equal (property_name, "Collections")) {
384 g_mutex_lock (&self->pv->mutex);
385 perform = self->pv->collections != NULL;
386 g_mutex_unlock (&self->pv->mutex);
389 secret_service_load_collections (self, self->pv->cancellable, NULL, NULL);
392 g_variant_unref (value);
396 secret_service_properties_changed (GDBusProxy *proxy,
397 GVariant *changed_properties,
398 const gchar* const *invalidated_properties)
400 SecretService *self = SECRET_SERVICE (proxy);
401 gchar *property_name;
405 g_object_freeze_notify (G_OBJECT (self));
407 g_variant_iter_init (&iter, changed_properties);
408 while (g_variant_iter_loop (&iter, "{sv}", &property_name, &value))
409 handle_property_changed (self, property_name, value);
411 g_object_thaw_notify (G_OBJECT (self));
415 secret_service_signal (GDBusProxy *proxy,
416 const gchar *sender_name,
417 const gchar *signal_name,
418 GVariant *parameters)
420 SecretService *self = SECRET_SERVICE (proxy);
421 SecretCollection *collection;
422 const gchar *collection_path;
423 GVariantBuilder builder;
424 gboolean found = FALSE;
431 * Remember that these signals come from a time before PropertiesChanged.
432 * We support them because they're in the spec, and ksecretservice uses them.
435 paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Collections");
437 /* A new collection was added, add it to the Collections property */
438 if (g_str_equal (signal_name, SECRET_SIGNAL_COLLECTION_CREATED)) {
439 g_variant_get (parameters, "(@o)", &value);
440 g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
441 g_variant_iter_init (&iter, paths);
442 while ((path = g_variant_iter_next_value (&iter)) != NULL) {
443 if (g_variant_equal (path, value)) {
447 g_variant_builder_add_value (&builder, path);
448 g_variant_unref (path);
451 g_variant_builder_add_value (&builder, value);
452 handle_property_changed (self, "Collections", g_variant_builder_end (&builder));
454 g_variant_builder_clear (&builder);
455 g_variant_unref (value);
457 /* A collection was deleted, remove it from the Collections property */
458 } else if (g_str_equal (signal_name, SECRET_SIGNAL_COLLECTION_DELETED)) {
459 g_variant_get (parameters, "(@o)", &value);
460 g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
461 g_variant_iter_init (&iter, paths);
462 while ((path = g_variant_iter_next_value (&iter)) != NULL) {
463 if (g_variant_equal (path, value))
466 g_variant_builder_add_value (&builder, path);
467 g_variant_unref (path);
470 handle_property_changed (self, "Collections", g_variant_builder_end (&builder));
471 g_variant_unref (value);
473 /* The collection changed, update it */
474 } else if (g_str_equal (signal_name, SECRET_SIGNAL_COLLECTION_CHANGED)) {
475 g_variant_get (parameters, "(&o)", &collection_path);
477 g_mutex_lock (&self->pv->mutex);
479 if (self->pv->collections)
480 collection = g_hash_table_lookup (self->pv->collections, collection_path);
484 g_object_ref (collection);
486 g_mutex_unlock (&self->pv->mutex);
489 secret_collection_refresh (collection);
490 g_object_unref (collection);
494 g_variant_unref (paths);
498 secret_service_class_init (SecretServiceClass *klass)
500 GObjectClass *object_class = G_OBJECT_CLASS (klass);
501 GDBusProxyClass *proxy_class = G_DBUS_PROXY_CLASS (klass);
503 object_class->get_property = secret_service_get_property;
504 object_class->set_property = secret_service_set_property;
505 object_class->dispose = secret_service_dispose;
506 object_class->finalize = secret_service_finalize;
508 proxy_class->g_properties_changed = secret_service_properties_changed;
509 proxy_class->g_signal = secret_service_signal;
511 klass->prompt_sync = secret_service_real_prompt_sync;
512 klass->prompt_async = secret_service_real_prompt_async;
513 klass->prompt_finish = secret_service_real_prompt_finish;
515 klass->item_gtype = SECRET_TYPE_ITEM;
516 klass->collection_gtype = SECRET_TYPE_COLLECTION;
519 * SecretService:flags:
521 * A set of flags describing which parts of the secret service have
524 g_object_class_install_property (object_class, PROP_FLAGS,
525 g_param_spec_flags ("flags", "Flags", "Service flags",
526 secret_service_flags_get_type (), SECRET_SERVICE_NONE,
527 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
530 * SecretService:collections:
532 * A list of #SecretCollection objects representing the collections in
533 * the Secret Service. This list may be %NULL if the collections have
536 * To load the collections, specify the %SECRET_SERVICE_LOAD_COLLECTIONS
537 * initialization flag when calling the secret_service_get() or
538 * secret_service_new() functions. Or call the secret_service_load_collections()
541 g_object_class_install_property (object_class, PROP_COLLECTIONS,
542 g_param_spec_boxed ("collections", "Collections", "Secret Service Collections",
543 _secret_list_get_type (), G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
545 g_type_class_add_private (klass, sizeof (SecretServicePrivate));
547 /* Initialize this error domain, registers dbus errors */
548 _secret_error_quark = secret_error_get_quark ();
552 GCancellable *cancellable;
553 SecretServiceFlags flags;
557 init_closure_free (gpointer data)
559 InitClosure *closure = data;
560 g_clear_object (&closure->cancellable);
561 g_slice_free (InitClosure, closure);
565 service_ensure_for_flags_sync (SecretService *self,
566 SecretServiceFlags flags,
567 GCancellable *cancellable,
570 if (flags & SECRET_SERVICE_OPEN_SESSION)
571 if (!secret_service_ensure_session_sync (self, cancellable, error))
574 if (flags & SECRET_SERVICE_LOAD_COLLECTIONS)
575 if (!secret_service_load_collections_sync (self, cancellable, error))
582 on_load_collections (GObject *source,
583 GAsyncResult *result,
586 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
587 SecretService *self = SECRET_SERVICE (source);
588 GError *error = NULL;
590 if (!secret_service_load_collections_finish (self, result, &error))
591 g_simple_async_result_take_error (res, error);
593 g_simple_async_result_complete (res);
594 g_object_unref (res);
598 on_ensure_session (GObject *source,
599 GAsyncResult *result,
602 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
603 InitClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
604 SecretService *self = SECRET_SERVICE (source);
605 GError *error = NULL;
607 if (!secret_service_ensure_session_finish (self, result, &error)) {
608 g_simple_async_result_take_error (res, error);
609 g_simple_async_result_complete (res);
611 } else if (closure->flags & SECRET_SERVICE_LOAD_COLLECTIONS) {
612 secret_service_load_collections (self, closure->cancellable,
613 on_load_collections, g_object_ref (res));
616 g_simple_async_result_complete_in_idle (res);
619 g_object_unref (res);
623 service_ensure_for_flags_async (SecretService *self,
624 SecretServiceFlags flags,
625 GSimpleAsyncResult *res)
627 InitClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
629 closure->flags = flags;
631 if (closure->flags & SECRET_SERVICE_OPEN_SESSION)
632 secret_service_ensure_session (self, closure->cancellable,
633 on_ensure_session, g_object_ref (res));
635 else if (closure->flags & SECRET_SERVICE_LOAD_COLLECTIONS)
636 secret_service_load_collections (self, closure->cancellable,
637 on_load_collections, g_object_ref (res));
640 g_simple_async_result_complete_in_idle (res);
644 secret_service_initable_init (GInitable *initable,
645 GCancellable *cancellable,
650 if (!secret_service_initable_parent_iface->init (initable, cancellable, error))
653 self = SECRET_SERVICE (initable);
654 return service_ensure_for_flags_sync (self, self->pv->init_flags, cancellable, error);
658 secret_service_initable_iface (GInitableIface *iface)
660 secret_service_initable_parent_iface = g_type_interface_peek_parent (iface);
662 iface->init = secret_service_initable_init;
666 on_init_base (GObject *source,
667 GAsyncResult *result,
670 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
671 SecretService *self = SECRET_SERVICE (source);
672 GError *error = NULL;
674 if (!secret_service_async_initable_parent_iface->init_finish (G_ASYNC_INITABLE (self),
676 g_simple_async_result_take_error (res, error);
677 g_simple_async_result_complete (res);
679 service_ensure_for_flags_async (self, self->pv->init_flags, res);
682 g_object_unref (res);
686 secret_service_async_initable_init_async (GAsyncInitable *initable,
688 GCancellable *cancellable,
689 GAsyncReadyCallback callback,
692 GSimpleAsyncResult *res;
693 InitClosure *closure;
695 res = g_simple_async_result_new (G_OBJECT (initable), callback, user_data,
696 secret_service_async_initable_init_async);
697 closure = g_slice_new0 (InitClosure);
698 closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
699 g_simple_async_result_set_op_res_gpointer (res, closure, init_closure_free);
701 secret_service_async_initable_parent_iface->init_async (initable, io_priority,
706 g_object_unref (res);
710 secret_service_async_initable_init_finish (GAsyncInitable *initable,
711 GAsyncResult *result,
714 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (initable),
715 secret_service_async_initable_init_async), FALSE);
717 if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
724 secret_service_async_initable_iface (GAsyncInitableIface *iface)
726 secret_service_async_initable_parent_iface = g_type_interface_peek_parent (iface);
728 iface->init_async = secret_service_async_initable_init_async;
729 iface->init_finish = secret_service_async_initable_init_finish;
733 _secret_service_set_default_bus_name (const gchar *bus_name)
735 g_return_if_fail (bus_name != NULL);
736 default_bus_name = bus_name;
740 * secret_service_get:
741 * @flags: flags for which service functionality to ensure is initialized
742 * @cancellable: optional cancellation object
743 * @callback: called when the operation completes
744 * @user_data: data to be passed to the callback
746 * Get a #SecretService proxy for the Secret Service. If such a proxy object
747 * already exists, then the same proxy is returned.
749 * If @flags contains any flags of which parts of the secret service to
750 * ensure are initialized, then those will be initialized before completing.
752 * This method will return immediately and complete asynchronously.
755 secret_service_get (SecretServiceFlags flags,
756 GCancellable *cancellable,
757 GAsyncReadyCallback callback,
760 SecretService *service = NULL;
761 GSimpleAsyncResult *res;
762 InitClosure *closure;
764 service = service_get_instance ();
766 /* Create a whole new service */
767 if (service == NULL) {
768 g_async_initable_new_async (SECRET_TYPE_SERVICE, G_PRIORITY_DEFAULT,
769 cancellable, callback, user_data,
770 "g-flags", G_DBUS_PROXY_FLAGS_NONE,
771 "g-interface-info", _secret_gen_service_interface_info (),
772 "g-name", default_bus_name,
773 "g-bus-type", G_BUS_TYPE_SESSION,
774 "g-object-path", SECRET_SERVICE_PATH,
775 "g-interface-name", SECRET_SERVICE_INTERFACE,
779 /* Just have to ensure that the service matches flags */
781 res = g_simple_async_result_new (G_OBJECT (service), callback,
782 user_data, secret_service_get);
783 closure = g_slice_new0 (InitClosure);
784 closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
785 closure->flags = flags;
786 g_simple_async_result_set_op_res_gpointer (res, closure, init_closure_free);
788 service_ensure_for_flags_async (service, flags, res);
790 g_object_unref (service);
791 g_object_unref (res);
796 * secret_service_get_finish:
797 * @result: the asynchronous result passed to the callback
798 * @error: location to place an error on failure
800 * Complete an asynchronous operation to get a #SecretService proxy for the
803 * Returns: (transfer full): a new reference to a #SecretService proxy, which
804 * should be released with g_object_unref().
807 secret_service_get_finish (GAsyncResult *result,
810 GObject *service = NULL;
811 GObject *source_object;
813 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
814 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
816 source_object = g_async_result_get_source_object (result);
818 /* Just ensuring that the service matches flags */
819 if (g_simple_async_result_is_valid (result, source_object, secret_service_get)) {
820 if (!g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
821 service = g_object_ref (source_object);
823 /* Creating a whole new service */
825 service = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error);
827 service_cache_instance (SECRET_SERVICE (service));
831 g_object_unref (source_object);
836 return SECRET_SERVICE (service);
840 * secret_service_get_sync:
841 * @flags: flags for which service functionality to ensure is initialized
842 * @cancellable: optional cancellation object
843 * @error: location to place an error on failure
845 * Get a #SecretService proxy for the Secret Service. If such a proxy object
846 * already exists, then the same proxy is returned.
848 * If @flags contains any flags of which parts of the secret service to
849 * ensure are initialized, then those will be initialized before returning.
851 * This method may block indefinitely and should not be used in user interface
854 * Returns: (transfer full): a new reference to a #SecretService proxy, which
855 * should be released with g_object_unref().
858 secret_service_get_sync (SecretServiceFlags flags,
859 GCancellable *cancellable,
862 SecretService *service = NULL;
864 service = service_get_instance ();
866 if (service == NULL) {
867 service = g_initable_new (SECRET_TYPE_SERVICE, cancellable, error,
868 "g-flags", G_DBUS_PROXY_FLAGS_NONE,
869 "g-interface-info", _secret_gen_service_interface_info (),
870 "g-name", default_bus_name,
871 "g-bus-type", G_BUS_TYPE_SESSION,
872 "g-object-path", SECRET_SERVICE_PATH,
873 "g-interface-name", SECRET_SERVICE_INTERFACE,
878 service_cache_instance (service);
881 if (!service_ensure_for_flags_sync (service, flags, cancellable, error)) {
882 g_object_unref (service);
891 * secret_service_disconnect:
893 * Disconnect the default #SecretService proxy returned by secret_service_get()
894 * and secret_service_get_sync().
896 * It is not necessary to call this function, but you may choose to do so at
897 * program exit. It is useful for testing that memory is not leaked.
899 * This function is safe to call at any time. But if other objects in this
900 * library are still referenced, then this will not result in all memory
904 secret_service_disconnect (void)
906 service_uncache_instance (NULL);
910 * secret_service_new:
911 * @service_gtype: the GType of the new secret service
912 * @service_bus_name: (allow-none): the D-Bus service name of the secret service
913 * @flags: flags for which service functionality to ensure is initialized
914 * @cancellable: optional cancellation object
915 * @callback: called when the operation completes
916 * @user_data: data to be passed to the callback
918 * Create a new #SecretService proxy for the Secret Service.
920 * This function is rarely used, see secret_service_get() instead.
922 * The @service_gtype argument should be set to %SECRET_TYPE_SERVICE or a the type
923 * of a derived class.
925 * If @flags contains any flags of which parts of the secret service to
926 * ensure are initialized, then those will be initialized before returning.
928 * If @service_bus_name is %NULL then the default is used.
930 * This method will return immediately and complete asynchronously.
933 secret_service_new (GType service_gtype,
934 const gchar *service_bus_name,
935 SecretServiceFlags flags,
936 GCancellable *cancellable,
937 GAsyncReadyCallback callback,
940 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
941 g_return_if_fail (g_type_is_a (service_gtype, SECRET_TYPE_SERVICE));
943 if (service_bus_name == NULL)
944 service_bus_name = default_bus_name;
946 g_async_initable_new_async (service_gtype, G_PRIORITY_DEFAULT,
947 cancellable, callback, user_data,
948 "g-flags", G_DBUS_PROXY_FLAGS_NONE,
949 "g-interface-info", _secret_gen_service_interface_info (),
950 "g-name", service_bus_name,
951 "g-bus-type", G_BUS_TYPE_SESSION,
952 "g-object-path", SECRET_SERVICE_PATH,
953 "g-interface-name", SECRET_SERVICE_INTERFACE,
959 * secret_service_new_finish:
960 * @result: the asynchronous result passed to the callback
961 * @error: location to place an error on failure
963 * Complete an asynchronous operation to create a new #SecretService proxy for
964 * the Secret Service.
966 * Returns: (transfer full): a new reference to a #SecretService proxy, which
967 * should be released with g_object_unref().
970 secret_service_new_finish (GAsyncResult *result,
973 GObject *source_object;
976 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
977 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
979 source_object = g_async_result_get_source_object (result);
980 object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
982 g_object_unref (source_object);
987 return SECRET_SERVICE (object);
991 * secret_service_new_sync:
992 * @service_gtype: the GType of the new secret service
993 * @service_bus_name: (allow-none): the D-Bus service name of the secret service
994 * @flags: flags for which service functionality to ensure is initialized
995 * @cancellable: optional cancellation object
996 * @error: location to place an error on failure
998 * Create a new #SecretService proxy for the Secret Service.
1000 * This function is rarely used, see secret_service_get_sync() instead.
1002 * The @service_gtype argument should be set to %SECRET_TYPE_SERVICE or a the
1003 * type of a derived class.
1005 * If @flags contains any flags of which parts of the secret service to
1006 * ensure are initialized, then those will be initialized before returning.
1008 * If @service_bus_name is %NULL then the default is used.
1010 * This method may block indefinitely and should not be used in user interface
1013 * Returns: (transfer full): a new reference to a #SecretService proxy, which
1014 * should be released with g_object_unref().
1017 secret_service_new_sync (GType service_gtype,
1018 const gchar *service_bus_name,
1019 SecretServiceFlags flags,
1020 GCancellable *cancellable,
1023 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
1024 g_return_val_if_fail (g_type_is_a (service_gtype, SECRET_TYPE_SERVICE), NULL);
1026 if (service_bus_name == NULL)
1027 service_bus_name = default_bus_name;
1029 return g_initable_new (service_gtype, cancellable, error,
1030 "g-flags", G_DBUS_PROXY_FLAGS_NONE,
1031 "g-interface-info", _secret_gen_service_interface_info (),
1032 "g-name", service_bus_name,
1033 "g-bus-type", G_BUS_TYPE_SESSION,
1034 "g-object-path", SECRET_SERVICE_PATH,
1035 "g-interface-name", SECRET_SERVICE_INTERFACE,
1041 * secret_service_get_flags:
1042 * @self: the secret service proxy
1044 * Get the flags representing what features of the #SecretService proxy
1045 * have been initialized.
1047 * Use secret_service_ensure_session() or secret_service_load_collections()
1048 * to initialize further features and change the flags.
1050 * Returns: the flags for features initialized
1053 secret_service_get_flags (SecretService *self)
1055 SecretServiceFlags flags = 0;
1057 g_return_val_if_fail (SECRET_IS_SERVICE (self), SECRET_SERVICE_NONE);
1059 g_mutex_lock (&self->pv->mutex);
1061 if (self->pv->session)
1062 flags |= SECRET_SERVICE_OPEN_SESSION;
1063 if (self->pv->collections)
1064 flags |= SECRET_SERVICE_LOAD_COLLECTIONS;
1066 g_mutex_unlock (&self->pv->mutex);
1072 * secret_service_get_collections:
1073 * @self: the secret service proxy
1075 * Get a list of #SecretCollection objects representing all the collections
1076 * in the secret service.
1078 * If the %SECRET_SERVICE_LOAD_COLLECTIONS flag was not specified when
1079 * initializing #SecretService proxy object, then this method will return
1080 * %NULL. Use secret_service_load_collections() to load the collections.
1082 * Returns: (transfer full) (element-type Secret.Collection) (allow-none): a
1083 * list of the collections in the secret service
1086 secret_service_get_collections (SecretService *self)
1088 GList *l, *collections;
1090 g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
1092 g_mutex_lock (&self->pv->mutex);
1094 if (self->pv->collections == NULL) {
1098 collections = g_hash_table_get_values (self->pv->collections);
1099 for (l = collections; l != NULL; l = g_list_next (l))
1100 g_object_ref (l->data);
1103 g_mutex_unlock (&self->pv->mutex);
1109 _secret_service_find_item_instance (SecretService *self,
1110 const gchar *item_path)
1112 SecretCollection *collection = NULL;
1113 gchar *collection_path;
1116 collection_path = _secret_util_parent_path (item_path);
1118 collection = _secret_service_find_collection_instance (self, collection_path);
1120 g_free (collection_path);
1122 if (collection == NULL)
1125 item = _secret_collection_find_item_instance (collection, item_path);
1126 g_object_unref (collection);
1132 _secret_service_find_collection_instance (SecretService *self,
1133 const gchar *collection_path)
1135 SecretCollection *collection = NULL;
1137 g_mutex_lock (&self->pv->mutex);
1138 if (self->pv->collections) {
1139 collection = g_hash_table_lookup (self->pv->collections, collection_path);
1140 if (collection != NULL)
1141 g_object_ref (collection);
1143 g_mutex_unlock (&self->pv->mutex);
1149 _secret_service_get_session (SecretService *self)
1151 SecretSession *session;
1153 g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
1155 g_mutex_lock (&self->pv->mutex);
1156 session = self->pv->session;
1157 g_mutex_unlock (&self->pv->mutex);
1163 _secret_service_take_session (SecretService *self,
1164 SecretSession *session)
1166 g_return_if_fail (SECRET_IS_SERVICE (self));
1167 g_return_if_fail (session != NULL);
1169 g_mutex_lock (&self->pv->mutex);
1170 if (self->pv->session == NULL)
1171 self->pv->session = session;
1173 _secret_session_free (session);
1174 g_mutex_unlock (&self->pv->mutex);
1178 * secret_service_get_session_algorithms:
1179 * @self: the secret service proxy
1181 * Get the set of algorithms being used to transfer secrets between this
1182 * secret service proxy and the Secret Service itself.
1184 * This will be %NULL if no session has been established. Use
1185 * secret_service_ensure_session() to establish a session.
1187 * Returns: (allow-none): a string representing the algorithms for transferring
1191 secret_service_get_session_algorithms (SecretService *self)
1193 SecretSession *session;
1194 const gchar *algorithms;
1196 g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
1198 g_mutex_lock (&self->pv->mutex);
1199 session = self->pv->session;
1200 algorithms = session ? _secret_session_get_algorithms (session) : NULL;
1201 g_mutex_unlock (&self->pv->mutex);
1203 /* Session never changes once established, so can return const */
1208 * secret_service_get_session_dbus_path:
1209 * @self: the secret service proxy
1211 * Get the D-Bus object path of the session object being used to transfer
1212 * secrets between this secret service proxy and the Secret Service itself.
1214 * This will be %NULL if no session has been established. Use
1215 * secret_service_ensure_session() to establish a session.
1217 * Returns: (allow-none): a string representing the D-Bus object path of the
1221 secret_service_get_session_dbus_path (SecretService *self)
1223 SecretSession *session;
1226 g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
1228 g_mutex_lock (&self->pv->mutex);
1229 session = self->pv->session;
1230 path = session ? _secret_session_get_path (session) : NULL;
1231 g_mutex_unlock (&self->pv->mutex);
1233 /* Session never changes once established, so can return const */
1238 * secret_service_ensure_session:
1239 * @self: the secret service
1240 * @cancellable: optional cancellation object
1241 * @callback: called when the operation completes
1242 * @user_data: data to be passed to the callback
1244 * Ensure that the #SecretService proxy has established a session with the
1245 * Secret Service. This session is used to transfer secrets.
1247 * It is not normally necessary to call this method, as the session is
1248 * established as necessary. You can also pass the %SECRET_SERVICE_OPEN_SESSION
1249 * to secret_service_get() in order to ensure that a session has been established
1250 * by the time you get the #SecretService proxy.
1252 * This method will return immediately and complete asynchronously.
1255 secret_service_ensure_session (SecretService *self,
1256 GCancellable *cancellable,
1257 GAsyncReadyCallback callback,
1260 GSimpleAsyncResult *res;
1261 SecretSession *session;
1263 g_return_if_fail (SECRET_IS_SERVICE (self));
1264 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1266 g_mutex_lock (&self->pv->mutex);
1267 session = self->pv->session;
1268 g_mutex_unlock (&self->pv->mutex);
1270 if (session == NULL) {
1271 _secret_session_open (self, cancellable, callback, user_data);
1274 res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
1275 secret_service_ensure_session);
1276 g_simple_async_result_complete_in_idle (res);
1277 g_object_unref (res);
1282 * secret_service_ensure_session_finish:
1283 * @self: the secret service
1284 * @result: the asynchronous result passed to the callback
1285 * @error: location to place an error on failure
1287 * Finish an asynchronous operation to ensure that the #SecretService proxy
1288 * has established a session with the Secret Service.
1290 * Returns: whether a session is established or not
1293 secret_service_ensure_session_finish (SecretService *self,
1294 GAsyncResult *result,
1297 g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
1298 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1300 if (!g_simple_async_result_is_valid (result, G_OBJECT (self),
1301 secret_service_ensure_session)) {
1302 if (!_secret_session_open_finish (result, error))
1306 g_return_val_if_fail (self->pv->session != NULL, FALSE);
1311 * secret_service_ensure_session_sync:
1312 * @self: the secret service
1313 * @cancellable: optional cancellation object
1314 * @error: location to place an error on failure
1316 * Ensure that the #SecretService proxy has established a session with the
1317 * Secret Service. This session is used to transfer secrets.
1319 * It is not normally necessary to call this method, as the session is
1320 * established as necessary. You can also pass the %SECRET_SERVICE_OPEN_SESSION
1321 * to secret_service_get_sync() in order to ensure that a session has been
1322 * established by the time you get the #SecretService proxy.
1324 * This method may block indefinitely and should not be used in user interface
1327 * Returns: whether a session is established or not
1330 secret_service_ensure_session_sync (SecretService *self,
1331 GCancellable *cancellable,
1337 g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
1338 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1339 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1341 sync = _secret_sync_new ();
1342 g_main_context_push_thread_default (sync->context);
1344 secret_service_ensure_session (self, cancellable,
1345 _secret_sync_on_result, sync);
1347 g_main_loop_run (sync->loop);
1349 ret = secret_service_ensure_session_finish (self, sync->result, error);
1351 g_main_context_pop_thread_default (sync->context);
1352 _secret_sync_free (sync);
1357 static SecretCollection *
1358 service_lookup_collection (SecretService *self,
1361 SecretCollection *collection = NULL;
1363 g_mutex_lock (&self->pv->mutex);
1365 if (self->pv->collections) {
1366 collection = g_hash_table_lookup (self->pv->collections, path);
1367 if (collection != NULL)
1368 g_object_ref (collection);
1371 g_mutex_unlock (&self->pv->mutex);
1377 service_update_collections (SecretService *self,
1378 GHashTable *collections)
1380 GHashTable *previous;
1382 g_hash_table_ref (collections);
1384 g_mutex_lock (&self->pv->mutex);
1386 previous = self->pv->collections;
1387 self->pv->collections = collections;
1389 g_mutex_unlock (&self->pv->mutex);
1391 if (previous != NULL)
1392 g_hash_table_unref (previous);
1394 g_object_notify (G_OBJECT (self), "collections");
1398 GCancellable *cancellable;
1399 GHashTable *collections;
1400 gint collections_loading;
1404 collections_table_new (void)
1406 return g_hash_table_new_full (g_str_hash, g_str_equal,
1407 g_free, g_object_unref);
1411 ensure_closure_free (gpointer data)
1413 EnsureClosure *closure = data;
1414 g_clear_object (&closure->cancellable);
1415 g_hash_table_unref (closure->collections);
1416 g_slice_free (EnsureClosure, closure);
1420 on_ensure_collection (GObject *source,
1421 GAsyncResult *result,
1424 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1425 SecretService *self = SECRET_SERVICE (g_async_result_get_source_object (user_data));
1426 EnsureClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
1427 SecretCollection *collection;
1429 GError *error = NULL;
1431 closure->collections_loading--;
1433 collection = secret_collection_new_for_dbus_path_finish (result, &error);
1436 g_simple_async_result_take_error (res, error);
1438 if (collection != NULL) {
1439 path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection));
1440 g_hash_table_insert (closure->collections, g_strdup (path), collection);
1443 if (closure->collections_loading == 0) {
1444 service_update_collections (self, closure->collections);
1445 g_simple_async_result_complete (res);
1448 g_object_unref (self);
1449 g_object_unref (res);
1453 * secret_service_load_collections:
1454 * @self: the secret service
1455 * @cancellable: optional cancellation object
1456 * @callback: called when the operation completes
1457 * @user_data: data to be passed to the callback
1459 * Ensure that the #SecretService proxy has loaded all the collections present
1460 * in the Secret Service. This affects the result of
1461 * secret_service_get_collections().
1463 * You can also pass the %SECRET_SERVICE_LOAD_COLLECTIONS to
1464 * secret_service_get_sync() in order to ensure that the collections have been
1465 * loaded by the time you get the #SecretService proxy.
1467 * This method will return immediately and complete asynchronously.
1470 secret_service_load_collections (SecretService *self,
1471 GCancellable *cancellable,
1472 GAsyncReadyCallback callback,
1475 EnsureClosure *closure;
1476 SecretCollection *collection;
1477 GSimpleAsyncResult *res;
1482 g_return_if_fail (SECRET_IS_SERVICE (self));
1483 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1485 paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Collections");
1486 g_return_if_fail (paths != NULL);
1488 res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
1489 secret_service_load_collections);
1490 closure = g_slice_new0 (EnsureClosure);
1491 closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
1492 closure->collections = collections_table_new ();
1493 g_simple_async_result_set_op_res_gpointer (res, closure, ensure_closure_free);
1495 g_variant_iter_init (&iter, paths);
1496 while (g_variant_iter_loop (&iter, "&o", &path)) {
1497 collection = service_lookup_collection (self, path);
1499 /* No such collection yet create a new one */
1500 if (collection == NULL) {
1501 secret_collection_new_for_dbus_path (self, path, SECRET_COLLECTION_LOAD_ITEMS,
1502 cancellable, on_ensure_collection, g_object_ref (res));
1503 closure->collections_loading++;
1505 g_hash_table_insert (closure->collections, g_strdup (path), collection);
1509 if (closure->collections_loading == 0) {
1510 service_update_collections (self, closure->collections);
1511 g_simple_async_result_complete_in_idle (res);
1514 g_variant_unref (paths);
1515 g_object_unref (res);
1519 * secret_service_load_collections_finish:
1520 * @self: the secret service
1521 * @result: the asynchronous result passed to the callback
1522 * @error: location to place an error on failure
1524 * Complete an asynchronous operation to ensure that the #SecretService proxy
1525 * has loaded all the collections present in the Secret Service.
1527 * Returns: whether the load was successful or not
1530 secret_service_load_collections_finish (SecretService *self,
1531 GAsyncResult *result,
1534 g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
1535 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1536 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
1537 secret_service_load_collections), FALSE);
1539 if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
1546 * secret_service_load_collections_sync:
1547 * @self: the secret service
1548 * @cancellable: optional cancellation object
1549 * @error: location to place an error on failure
1551 * Ensure that the #SecretService proxy has loaded all the collections present
1552 * in the Secret Service. This affects the result of
1553 * secret_service_get_collections().
1555 * You can also pass the %SECRET_SERVICE_LOAD_COLLECTIONS to
1556 * secret_service_get_sync() in order to ensure that the collections have been
1557 * loaded by the time you get the #SecretService proxy.
1559 * This method may block indefinitely and should not be used in user interface
1562 * Returns: whether the load was successful or not
1565 secret_service_load_collections_sync (SecretService *self,
1566 GCancellable *cancellable,
1569 SecretCollection *collection;
1570 GHashTable *collections;
1574 gboolean ret = TRUE;
1576 g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
1577 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1578 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1580 paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Collections");
1581 g_return_val_if_fail (paths != NULL, FALSE);
1583 collections = collections_table_new ();
1585 g_variant_iter_init (&iter, paths);
1586 while (g_variant_iter_next (&iter, "&o", &path)) {
1587 collection = service_lookup_collection (self, path);
1589 /* No such collection yet create a new one */
1590 if (collection == NULL) {
1591 collection = secret_collection_new_for_dbus_path_sync (self, path,
1592 SECRET_COLLECTION_LOAD_ITEMS,
1593 cancellable, error);
1594 if (collection == NULL) {
1600 g_hash_table_insert (collections, g_strdup (path), collection);
1604 service_update_collections (self, collections);
1606 g_hash_table_unref (collections);
1607 g_variant_unref (paths);
1612 * secret_service_prompt_sync:
1613 * @self: the secret service
1614 * @prompt: the prompt
1615 * @cancellable: optional cancellation object
1616 * @return_type: the variant type of the prompt result
1617 * @error: location to place an error on failure
1619 * Perform prompting for a #SecretPrompt.
1621 * Runs a prompt and performs the prompting. Returns a variant result if the
1622 * prompt was completed and not dismissed. The type of result depends on the
1623 * action the prompt is completing, and is defined in the Secret Service DBus
1624 * API specification.
1626 * This function is called by other parts of this library to handle prompts
1627 * for the various actions that can require prompting.
1629 * Override the #SecretServiceClass <literal>prompt_sync</literal> virtual method
1630 * to change the behavior of the propmting. The default behavior is to simply
1631 * run secret_prompt_perform_sync() on the prompt.
1633 * Returns: (transfer full): %NULL if the prompt was dismissed or an error occurred,
1634 * a variant result if the prompt was successful
1637 secret_service_prompt_sync (SecretService *self,
1638 SecretPrompt *prompt,
1639 GCancellable *cancellable,
1640 const GVariantType *return_type,
1643 SecretServiceClass *klass;
1645 g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
1646 g_return_val_if_fail (SECRET_IS_PROMPT (prompt), NULL);
1647 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
1648 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1650 klass = SECRET_SERVICE_GET_CLASS (self);
1651 g_return_val_if_fail (klass->prompt_sync != NULL, NULL);
1653 return (klass->prompt_sync) (self, prompt, cancellable, return_type, error);
1657 * secret_service_prompt:
1658 * @self: the secret service
1659 * @prompt: the prompt
1660 * @cancellable: optional cancellation object
1661 * @callback: called when the operation completes
1662 * @user_data: data to be passed to the callback
1664 * Perform prompting for a #SecretPrompt.
1666 * This function is called by other parts of this library to handle prompts
1667 * for the various actions that can require prompting.
1669 * Override the #SecretServiceClass <literal>prompt_async</literal> virtual method
1670 * to change the behavior of the propmting. The default behavior is to simply
1671 * run secret_prompt_perform() on the prompt.
1674 secret_service_prompt (SecretService *self,
1675 SecretPrompt *prompt,
1676 GCancellable *cancellable,
1677 GAsyncReadyCallback callback,
1680 SecretServiceClass *klass;
1682 g_return_if_fail (SECRET_IS_SERVICE (self));
1683 g_return_if_fail (SECRET_IS_PROMPT (prompt));
1684 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1686 klass = SECRET_SERVICE_GET_CLASS (self);
1687 g_return_if_fail (klass->prompt_async != NULL);
1689 (klass->prompt_async) (self, prompt, cancellable, callback, user_data);
1693 * secret_service_prompt_finish:
1694 * @self: the secret service
1695 * @result: the asynchronous result passed to the callback
1696 * @return_type: the variant type of the prompt result
1697 * @error: location to place an error on failure
1699 * Complete asynchronous operation to perform prompting for a #SecretPrompt.
1701 * Returns a variant result if the prompt was completed and not dismissed. The
1702 * type of result depends on the action the prompt is completing, and is defined
1703 * in the Secret Service DBus API specification.
1705 * Returns: (transfer full): %NULL if the prompt was dismissed or an error occurred,
1706 * a variant result if the prompt was successful
1709 secret_service_prompt_finish (SecretService *self,
1710 GAsyncResult *result,
1711 const GVariantType *return_type,
1714 SecretServiceClass *klass;
1716 g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
1717 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
1718 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1720 klass = SECRET_SERVICE_GET_CLASS (self);
1721 g_return_val_if_fail (klass->prompt_finish != NULL, NULL);
1723 return (klass->prompt_finish) (self, result, return_type, error);