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.
69 * These functions have an unstable API and may change across versions. Use
70 * <literal>libsecret-unstable</literal> package to access them.
78 * A proxy object representing the Secret Service.
83 * @parent_class: the parent class
84 * @collection_gtype: the #GType of the #SecretCollection objects instantiated
85 * by the #SecretService proxy
86 * @item_gtype: the #GType of the #SecretItem objects instantiated by the
87 * #SecretService proxy
88 * @prompt_async: called to perform asynchronous prompting when necessary
89 * @prompt_finish: called to complete an asynchronous prompt operation
90 * @prompt_sync: called to perform synchronous prompting when necessary
92 * The class for #SecretService.
97 * @SECRET_SERVICE_NONE: no flags for initializing the #SecretService
98 * @SECRET_SERVICE_OPEN_SESSION: establish a session for transfer of secrets
99 * while initializing the #SecretService
100 * @SECRET_SERVICE_LOAD_COLLECTIONS: load collections while initializing the
103 * Flags which determine which parts of the #SecretService proxy are initialized
104 * during a secret_service_get() or secret_service_new() operation.
107 EGG_SECURE_GLIB_DEFINITIONS ();
109 GQuark _secret_error_quark = 0;
110 static const gchar *default_bus_name = SECRET_SERVICE_BUS_NAME;
118 struct _SecretServicePrivate {
119 /* No change between construct and finalize */
120 GCancellable *cancellable;
121 SecretServiceFlags init_flags;
123 /* Locked by mutex */
126 GHashTable *collections;
129 G_LOCK_DEFINE (service_instance);
130 static gpointer service_instance = NULL;
131 static guint service_watch = 0;
133 static GInitableIface *secret_service_initable_parent_iface = NULL;
135 static GAsyncInitableIface *secret_service_async_initable_parent_iface = NULL;
137 static void secret_service_initable_iface (GInitableIface *iface);
139 static void secret_service_async_initable_iface (GAsyncInitableIface *iface);
141 G_DEFINE_TYPE_WITH_CODE (SecretService, secret_service, G_TYPE_DBUS_PROXY,
142 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, secret_service_initable_iface);
143 G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, secret_service_async_initable_iface);
146 static SecretService *
147 service_get_instance (void)
149 SecretService *instance = NULL;
151 G_LOCK (service_instance);
152 if (service_instance != NULL)
153 instance = g_object_ref (service_instance);
154 G_UNLOCK (service_instance);
160 service_uncache_instance (SecretService *which)
162 SecretService *instance = NULL;
164 gboolean matched = FALSE;
166 G_LOCK (service_instance);
167 if (which == NULL || service_instance == which) {
168 instance = service_instance;
169 service_instance = NULL;
170 watch = service_watch;
174 G_UNLOCK (service_instance);
176 if (instance != NULL)
177 g_object_unref (instance);
179 g_bus_unwatch_name (watch);
185 on_service_instance_vanished (GDBusConnection *connection,
189 if (!service_uncache_instance (user_data)) {
190 g_warning ("Global default SecretService instance out of sync "
191 "with the watch for its DBus name");
196 service_cache_instance (SecretService *instance)
201 g_object_ref (instance);
202 proxy = G_DBUS_PROXY (instance);
203 watch = g_bus_watch_name_on_connection (g_dbus_proxy_get_connection (proxy),
204 g_dbus_proxy_get_name (proxy),
205 G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
206 NULL, on_service_instance_vanished,
209 G_LOCK (service_instance);
210 if (service_instance == NULL) {
211 service_instance = instance;
213 service_watch = watch;
216 G_UNLOCK (service_instance);
218 if (instance != NULL)
219 g_object_unref (instance);
221 g_bus_unwatch_name (watch);
225 secret_service_init (SecretService *self)
227 self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, SECRET_TYPE_SERVICE,
228 SecretServicePrivate);
230 g_mutex_init (&self->pv->mutex);
231 self->pv->cancellable = g_cancellable_new ();
235 secret_service_get_property (GObject *obj,
240 SecretService *self = SECRET_SERVICE (obj);
244 g_value_set_flags (value, secret_service_get_flags (self));
246 case PROP_COLLECTIONS:
247 g_value_take_boxed (value, secret_service_get_collections (self));
250 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
256 secret_service_set_property (GObject *obj,
261 SecretService *self = SECRET_SERVICE (obj);
265 self->pv->init_flags = g_value_get_flags (value);
268 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
274 secret_service_dispose (GObject *obj)
276 SecretService *self = SECRET_SERVICE (obj);
278 g_cancellable_cancel (self->pv->cancellable);
280 G_OBJECT_CLASS (secret_service_parent_class)->dispose (obj);
284 secret_service_finalize (GObject *obj)
286 SecretService *self = SECRET_SERVICE (obj);
288 _secret_session_free (self->pv->session);
289 if (self->pv->collections)
290 g_hash_table_destroy (self->pv->collections);
291 g_clear_object (&self->pv->cancellable);
292 g_mutex_clear (&self->pv->mutex);
294 G_OBJECT_CLASS (secret_service_parent_class)->finalize (obj);
298 secret_service_real_prompt_sync (SecretService *self,
299 SecretPrompt *prompt,
300 GCancellable *cancellable,
301 const GVariantType *return_type,
304 return secret_prompt_perform_sync (prompt, 0, cancellable, return_type, error);
308 on_real_prompt_completed (GObject *source,
309 GAsyncResult *result,
312 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
313 GError *error = NULL;
316 retval = secret_prompt_perform_finish (SECRET_PROMPT (source), result, NULL, &error);
318 g_simple_async_result_set_op_res_gpointer (res, retval, (GDestroyNotify)g_variant_unref);
320 g_simple_async_result_take_error (res, error);
321 g_simple_async_result_complete (res);
322 g_object_unref (res);
326 secret_service_real_prompt_async (SecretService *self,
327 SecretPrompt *prompt,
328 GCancellable *cancellable,
329 GAsyncReadyCallback callback,
332 GSimpleAsyncResult *res;
334 res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
335 secret_service_real_prompt_async);
337 secret_prompt_perform (prompt, 0, cancellable,
338 on_real_prompt_completed,
341 g_object_unref (res);
345 secret_service_real_prompt_finish (SecretService *self,
346 GAsyncResult *result,
347 const GVariantType *return_type,
350 GSimpleAsyncResult *res;
354 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
355 secret_service_real_prompt_async), NULL);
357 res = G_SIMPLE_ASYNC_RESULT (result);
358 if (g_simple_async_result_propagate_error (res, error))
361 retval = g_simple_async_result_get_op_res_gpointer (res);
365 if (return_type != NULL && !g_variant_is_of_type (retval, return_type)) {
366 string = g_variant_type_dup_string (return_type);
367 g_warning ("received unexpected result type %s from prompt's Completed signal instead of expected %s",
368 g_variant_get_type_string (retval), string);
373 return g_variant_ref (retval);
377 handle_property_changed (SecretService *self,
378 const gchar *property_name,
383 g_variant_ref_sink (value);
385 if (g_str_equal (property_name, "Collections")) {
387 g_mutex_lock (&self->pv->mutex);
388 perform = self->pv->collections != NULL;
389 g_mutex_unlock (&self->pv->mutex);
392 secret_service_load_collections (self, self->pv->cancellable, NULL, NULL);
395 g_variant_unref (value);
399 secret_service_properties_changed (GDBusProxy *proxy,
400 GVariant *changed_properties,
401 const gchar* const *invalidated_properties)
403 SecretService *self = SECRET_SERVICE (proxy);
404 gchar *property_name;
408 g_object_freeze_notify (G_OBJECT (self));
410 g_variant_iter_init (&iter, changed_properties);
411 while (g_variant_iter_loop (&iter, "{sv}", &property_name, &value))
412 handle_property_changed (self, property_name, value);
414 g_object_thaw_notify (G_OBJECT (self));
418 secret_service_signal (GDBusProxy *proxy,
419 const gchar *sender_name,
420 const gchar *signal_name,
421 GVariant *parameters)
423 SecretService *self = SECRET_SERVICE (proxy);
424 SecretCollection *collection;
425 const gchar *collection_path;
426 GVariantBuilder builder;
427 gboolean found = FALSE;
434 * Remember that these signals come from a time before PropertiesChanged.
435 * We support them because they're in the spec, and ksecretservice uses them.
438 paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Collections");
440 /* A new collection was added, add it to the Collections property */
441 if (g_str_equal (signal_name, SECRET_SIGNAL_COLLECTION_CREATED)) {
442 g_variant_get (parameters, "(@o)", &value);
443 g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
444 g_variant_iter_init (&iter, paths);
445 while ((path = g_variant_iter_next_value (&iter)) != NULL) {
446 if (g_variant_equal (path, value)) {
450 g_variant_builder_add_value (&builder, path);
451 g_variant_unref (path);
454 g_variant_builder_add_value (&builder, value);
455 handle_property_changed (self, "Collections", g_variant_builder_end (&builder));
457 g_variant_builder_clear (&builder);
458 g_variant_unref (value);
460 /* A collection was deleted, remove it from the Collections property */
461 } else if (g_str_equal (signal_name, SECRET_SIGNAL_COLLECTION_DELETED)) {
462 g_variant_get (parameters, "(@o)", &value);
463 g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
464 g_variant_iter_init (&iter, paths);
465 while ((path = g_variant_iter_next_value (&iter)) != NULL) {
466 if (g_variant_equal (path, value))
469 g_variant_builder_add_value (&builder, path);
470 g_variant_unref (path);
473 handle_property_changed (self, "Collections", g_variant_builder_end (&builder));
474 g_variant_unref (value);
476 /* The collection changed, update it */
477 } else if (g_str_equal (signal_name, SECRET_SIGNAL_COLLECTION_CHANGED)) {
478 g_variant_get (parameters, "(&o)", &collection_path);
480 g_mutex_lock (&self->pv->mutex);
482 if (self->pv->collections)
483 collection = g_hash_table_lookup (self->pv->collections, collection_path);
487 g_object_ref (collection);
489 g_mutex_unlock (&self->pv->mutex);
492 secret_collection_refresh (collection);
493 g_object_unref (collection);
497 g_variant_unref (paths);
501 secret_service_class_init (SecretServiceClass *klass)
503 GObjectClass *object_class = G_OBJECT_CLASS (klass);
504 GDBusProxyClass *proxy_class = G_DBUS_PROXY_CLASS (klass);
506 object_class->get_property = secret_service_get_property;
507 object_class->set_property = secret_service_set_property;
508 object_class->dispose = secret_service_dispose;
509 object_class->finalize = secret_service_finalize;
511 proxy_class->g_properties_changed = secret_service_properties_changed;
512 proxy_class->g_signal = secret_service_signal;
514 klass->prompt_sync = secret_service_real_prompt_sync;
515 klass->prompt_async = secret_service_real_prompt_async;
516 klass->prompt_finish = secret_service_real_prompt_finish;
518 klass->item_gtype = SECRET_TYPE_ITEM;
519 klass->collection_gtype = SECRET_TYPE_COLLECTION;
522 * SecretService:flags:
524 * A set of flags describing which parts of the secret service have
527 g_object_class_install_property (object_class, PROP_FLAGS,
528 g_param_spec_flags ("flags", "Flags", "Service flags",
529 secret_service_flags_get_type (), SECRET_SERVICE_NONE,
530 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
533 * SecretService:collections:
535 * A list of #SecretCollection objects representing the collections in
536 * the Secret Service. This list may be %NULL if the collections have
539 * To load the collections, specify the %SECRET_SERVICE_LOAD_COLLECTIONS
540 * initialization flag when calling the secret_service_get() or
541 * secret_service_new() functions. Or call the secret_service_load_collections()
544 g_object_class_install_property (object_class, PROP_COLLECTIONS,
545 g_param_spec_boxed ("collections", "Collections", "Secret Service Collections",
546 _secret_list_get_type (), G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
548 g_type_class_add_private (klass, sizeof (SecretServicePrivate));
550 /* Initialize this error domain, registers dbus errors */
551 _secret_error_quark = secret_error_get_quark ();
555 GCancellable *cancellable;
556 SecretServiceFlags flags;
560 init_closure_free (gpointer data)
562 InitClosure *closure = data;
563 g_clear_object (&closure->cancellable);
564 g_slice_free (InitClosure, closure);
568 service_ensure_for_flags_sync (SecretService *self,
569 SecretServiceFlags flags,
570 GCancellable *cancellable,
573 if (flags & SECRET_SERVICE_OPEN_SESSION)
574 if (!secret_service_ensure_session_sync (self, cancellable, error))
577 if (flags & SECRET_SERVICE_LOAD_COLLECTIONS)
578 if (!secret_service_load_collections_sync (self, cancellable, error))
585 on_load_collections (GObject *source,
586 GAsyncResult *result,
589 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
590 SecretService *self = SECRET_SERVICE (source);
591 GError *error = NULL;
593 if (!secret_service_load_collections_finish (self, result, &error))
594 g_simple_async_result_take_error (res, error);
596 g_simple_async_result_complete (res);
597 g_object_unref (res);
601 on_ensure_session (GObject *source,
602 GAsyncResult *result,
605 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
606 InitClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
607 SecretService *self = SECRET_SERVICE (source);
608 GError *error = NULL;
610 if (!secret_service_ensure_session_finish (self, result, &error)) {
611 g_simple_async_result_take_error (res, error);
612 g_simple_async_result_complete (res);
614 } else if (closure->flags & SECRET_SERVICE_LOAD_COLLECTIONS) {
615 secret_service_load_collections (self, closure->cancellable,
616 on_load_collections, g_object_ref (res));
619 g_simple_async_result_complete_in_idle (res);
622 g_object_unref (res);
626 service_ensure_for_flags_async (SecretService *self,
627 SecretServiceFlags flags,
628 GSimpleAsyncResult *res)
630 InitClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
632 closure->flags = flags;
634 if (closure->flags & SECRET_SERVICE_OPEN_SESSION)
635 secret_service_ensure_session (self, closure->cancellable,
636 on_ensure_session, g_object_ref (res));
638 else if (closure->flags & SECRET_SERVICE_LOAD_COLLECTIONS)
639 secret_service_load_collections (self, closure->cancellable,
640 on_load_collections, g_object_ref (res));
643 g_simple_async_result_complete_in_idle (res);
647 secret_service_initable_init (GInitable *initable,
648 GCancellable *cancellable,
653 if (!secret_service_initable_parent_iface->init (initable, cancellable, error))
656 self = SECRET_SERVICE (initable);
657 return service_ensure_for_flags_sync (self, self->pv->init_flags, cancellable, error);
661 secret_service_initable_iface (GInitableIface *iface)
663 secret_service_initable_parent_iface = g_type_interface_peek_parent (iface);
665 iface->init = secret_service_initable_init;
669 on_init_base (GObject *source,
670 GAsyncResult *result,
673 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
674 SecretService *self = SECRET_SERVICE (source);
675 GError *error = NULL;
677 if (!secret_service_async_initable_parent_iface->init_finish (G_ASYNC_INITABLE (self),
679 g_simple_async_result_take_error (res, error);
680 g_simple_async_result_complete (res);
682 service_ensure_for_flags_async (self, self->pv->init_flags, res);
685 g_object_unref (res);
689 secret_service_async_initable_init_async (GAsyncInitable *initable,
691 GCancellable *cancellable,
692 GAsyncReadyCallback callback,
695 GSimpleAsyncResult *res;
696 InitClosure *closure;
698 res = g_simple_async_result_new (G_OBJECT (initable), callback, user_data,
699 secret_service_async_initable_init_async);
700 closure = g_slice_new0 (InitClosure);
701 closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
702 g_simple_async_result_set_op_res_gpointer (res, closure, init_closure_free);
704 secret_service_async_initable_parent_iface->init_async (initable, io_priority,
709 g_object_unref (res);
713 secret_service_async_initable_init_finish (GAsyncInitable *initable,
714 GAsyncResult *result,
717 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (initable),
718 secret_service_async_initable_init_async), FALSE);
720 if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
727 secret_service_async_initable_iface (GAsyncInitableIface *iface)
729 secret_service_async_initable_parent_iface = g_type_interface_peek_parent (iface);
731 iface->init_async = secret_service_async_initable_init_async;
732 iface->init_finish = secret_service_async_initable_init_finish;
736 _secret_service_set_default_bus_name (const gchar *bus_name)
738 g_return_if_fail (bus_name != NULL);
739 default_bus_name = bus_name;
743 * secret_service_get:
744 * @flags: flags for which service functionality to ensure is initialized
745 * @cancellable: optional cancellation object
746 * @callback: called when the operation completes
747 * @user_data: data to be passed to the callback
749 * Get a #SecretService proxy for the Secret Service. If such a proxy object
750 * already exists, then the same proxy is returned.
752 * If @flags contains any flags of which parts of the secret service to
753 * ensure are initialized, then those will be initialized before completing.
755 * This method will return immediately and complete asynchronously.
758 secret_service_get (SecretServiceFlags flags,
759 GCancellable *cancellable,
760 GAsyncReadyCallback callback,
763 SecretService *service = NULL;
764 GSimpleAsyncResult *res;
765 InitClosure *closure;
767 service = service_get_instance ();
769 /* Create a whole new service */
770 if (service == NULL) {
771 g_async_initable_new_async (SECRET_TYPE_SERVICE, G_PRIORITY_DEFAULT,
772 cancellable, callback, user_data,
773 "g-flags", G_DBUS_PROXY_FLAGS_NONE,
774 "g-interface-info", _secret_gen_service_interface_info (),
775 "g-name", default_bus_name,
776 "g-bus-type", G_BUS_TYPE_SESSION,
777 "g-object-path", SECRET_SERVICE_PATH,
778 "g-interface-name", SECRET_SERVICE_INTERFACE,
782 /* Just have to ensure that the service matches flags */
784 res = g_simple_async_result_new (G_OBJECT (service), callback,
785 user_data, secret_service_get);
786 closure = g_slice_new0 (InitClosure);
787 closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
788 closure->flags = flags;
789 g_simple_async_result_set_op_res_gpointer (res, closure, init_closure_free);
791 service_ensure_for_flags_async (service, flags, res);
793 g_object_unref (service);
794 g_object_unref (res);
799 * secret_service_get_finish:
800 * @result: the asynchronous result passed to the callback
801 * @error: location to place an error on failure
803 * Complete an asynchronous operation to get a #SecretService proxy for the
806 * Returns: (transfer full): a new reference to a #SecretService proxy, which
807 * should be released with g_object_unref().
810 secret_service_get_finish (GAsyncResult *result,
813 GObject *service = NULL;
814 GObject *source_object;
816 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
817 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
819 source_object = g_async_result_get_source_object (result);
821 /* Just ensuring that the service matches flags */
822 if (g_simple_async_result_is_valid (result, source_object, secret_service_get)) {
823 if (!g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
824 service = g_object_ref (source_object);
826 /* Creating a whole new service */
828 service = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error);
830 service_cache_instance (SECRET_SERVICE (service));
834 g_object_unref (source_object);
839 return SECRET_SERVICE (service);
843 * secret_service_get_sync:
844 * @flags: flags for which service functionality to ensure is initialized
845 * @cancellable: optional cancellation object
846 * @error: location to place an error on failure
848 * Get a #SecretService proxy for the Secret Service. If such a proxy object
849 * already exists, then the same proxy is returned.
851 * If @flags contains any flags of which parts of the secret service to
852 * ensure are initialized, then those will be initialized before returning.
854 * This method may block indefinitely and should not be used in user interface
857 * Returns: (transfer full): a new reference to a #SecretService proxy, which
858 * should be released with g_object_unref().
861 secret_service_get_sync (SecretServiceFlags flags,
862 GCancellable *cancellable,
865 SecretService *service = NULL;
867 service = service_get_instance ();
869 if (service == NULL) {
870 service = g_initable_new (SECRET_TYPE_SERVICE, cancellable, error,
871 "g-flags", G_DBUS_PROXY_FLAGS_NONE,
872 "g-interface-info", _secret_gen_service_interface_info (),
873 "g-name", default_bus_name,
874 "g-bus-type", G_BUS_TYPE_SESSION,
875 "g-object-path", SECRET_SERVICE_PATH,
876 "g-interface-name", SECRET_SERVICE_INTERFACE,
881 service_cache_instance (service);
884 if (!service_ensure_for_flags_sync (service, flags, cancellable, error)) {
885 g_object_unref (service);
894 * secret_service_disconnect:
896 * Disconnect the default #SecretService proxy returned by secret_service_get()
897 * and secret_service_get_sync().
899 * It is not necessary to call this function, but you may choose to do so at
900 * program exit. It is useful for testing that memory is not leaked.
902 * This function is safe to call at any time. But if other objects in this
903 * library are still referenced, then this will not result in all memory
907 secret_service_disconnect (void)
909 service_uncache_instance (NULL);
913 * secret_service_new:
914 * @service_gtype: the GType of the new secret service
915 * @service_bus_name: (allow-none): the D-Bus service name of the secret service
916 * @flags: flags for which service functionality to ensure is initialized
917 * @cancellable: optional cancellation object
918 * @callback: called when the operation completes
919 * @user_data: data to be passed to the callback
921 * Create a new #SecretService proxy for the Secret Service.
923 * This function is rarely used, see secret_service_get() instead.
925 * The @service_gtype argument should be set to %SECRET_TYPE_SERVICE or a the type
926 * of a derived class.
928 * If @flags contains any flags of which parts of the secret service to
929 * ensure are initialized, then those will be initialized before returning.
931 * If @service_bus_name is %NULL then the default is used.
933 * This method will return immediately and complete asynchronously.
936 secret_service_new (GType service_gtype,
937 const gchar *service_bus_name,
938 SecretServiceFlags flags,
939 GCancellable *cancellable,
940 GAsyncReadyCallback callback,
943 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
944 g_return_if_fail (g_type_is_a (service_gtype, SECRET_TYPE_SERVICE));
946 if (service_bus_name == NULL)
947 service_bus_name = default_bus_name;
949 g_async_initable_new_async (service_gtype, G_PRIORITY_DEFAULT,
950 cancellable, callback, user_data,
951 "g-flags", G_DBUS_PROXY_FLAGS_NONE,
952 "g-interface-info", _secret_gen_service_interface_info (),
953 "g-name", service_bus_name,
954 "g-bus-type", G_BUS_TYPE_SESSION,
955 "g-object-path", SECRET_SERVICE_PATH,
956 "g-interface-name", SECRET_SERVICE_INTERFACE,
962 * secret_service_new_finish:
963 * @result: the asynchronous result passed to the callback
964 * @error: location to place an error on failure
966 * Complete an asynchronous operation to create a new #SecretService proxy for
967 * the Secret Service.
969 * Returns: (transfer full): a new reference to a #SecretService proxy, which
970 * should be released with g_object_unref().
973 secret_service_new_finish (GAsyncResult *result,
976 GObject *source_object;
979 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
980 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
982 source_object = g_async_result_get_source_object (result);
983 object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
985 g_object_unref (source_object);
990 return SECRET_SERVICE (object);
994 * secret_service_new_sync:
995 * @service_gtype: the GType of the new secret service
996 * @service_bus_name: (allow-none): the D-Bus service name of the secret service
997 * @flags: flags for which service functionality to ensure is initialized
998 * @cancellable: optional cancellation object
999 * @error: location to place an error on failure
1001 * Create a new #SecretService proxy for the Secret Service.
1003 * This function is rarely used, see secret_service_get_sync() instead.
1005 * The @service_gtype argument should be set to %SECRET_TYPE_SERVICE or a the
1006 * type of a derived class.
1008 * If @flags contains any flags of which parts of the secret service to
1009 * ensure are initialized, then those will be initialized before returning.
1011 * If @service_bus_name is %NULL then the default is used.
1013 * This method may block indefinitely and should not be used in user interface
1016 * Returns: (transfer full): a new reference to a #SecretService proxy, which
1017 * should be released with g_object_unref().
1020 secret_service_new_sync (GType service_gtype,
1021 const gchar *service_bus_name,
1022 SecretServiceFlags flags,
1023 GCancellable *cancellable,
1026 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
1027 g_return_val_if_fail (g_type_is_a (service_gtype, SECRET_TYPE_SERVICE), NULL);
1029 if (service_bus_name == NULL)
1030 service_bus_name = default_bus_name;
1032 return g_initable_new (service_gtype, cancellable, error,
1033 "g-flags", G_DBUS_PROXY_FLAGS_NONE,
1034 "g-interface-info", _secret_gen_service_interface_info (),
1035 "g-name", service_bus_name,
1036 "g-bus-type", G_BUS_TYPE_SESSION,
1037 "g-object-path", SECRET_SERVICE_PATH,
1038 "g-interface-name", SECRET_SERVICE_INTERFACE,
1044 * secret_service_get_flags:
1045 * @self: the secret service proxy
1047 * Get the flags representing what features of the #SecretService proxy
1048 * have been initialized.
1050 * Use secret_service_ensure_session() or secret_service_load_collections()
1051 * to initialize further features and change the flags.
1053 * Returns: the flags for features initialized
1056 secret_service_get_flags (SecretService *self)
1058 SecretServiceFlags flags = 0;
1060 g_return_val_if_fail (SECRET_IS_SERVICE (self), SECRET_SERVICE_NONE);
1062 g_mutex_lock (&self->pv->mutex);
1064 if (self->pv->session)
1065 flags |= SECRET_SERVICE_OPEN_SESSION;
1066 if (self->pv->collections)
1067 flags |= SECRET_SERVICE_LOAD_COLLECTIONS;
1069 g_mutex_unlock (&self->pv->mutex);
1075 * secret_service_get_collections:
1076 * @self: the secret service proxy
1078 * Get a list of #SecretCollection objects representing all the collections
1079 * in the secret service.
1081 * If the %SECRET_SERVICE_LOAD_COLLECTIONS flag was not specified when
1082 * initializing #SecretService proxy object, then this method will return
1083 * %NULL. Use secret_service_load_collections() to load the collections.
1085 * Returns: (transfer full) (element-type SecretUnstable.Collection) (allow-none): a
1086 * list of the collections in the secret service
1089 secret_service_get_collections (SecretService *self)
1091 GList *l, *collections;
1093 g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
1095 g_mutex_lock (&self->pv->mutex);
1097 if (self->pv->collections == NULL) {
1101 collections = g_hash_table_get_values (self->pv->collections);
1102 for (l = collections; l != NULL; l = g_list_next (l))
1103 g_object_ref (l->data);
1106 g_mutex_unlock (&self->pv->mutex);
1112 _secret_service_find_item_instance (SecretService *self,
1113 const gchar *item_path)
1115 SecretCollection *collection = NULL;
1116 gchar *collection_path;
1119 collection_path = _secret_util_parent_path (item_path);
1121 collection = _secret_service_find_collection_instance (self, collection_path);
1123 g_free (collection_path);
1125 if (collection == NULL)
1128 item = _secret_collection_find_item_instance (collection, item_path);
1129 g_object_unref (collection);
1135 _secret_service_find_collection_instance (SecretService *self,
1136 const gchar *collection_path)
1138 SecretCollection *collection = NULL;
1140 g_mutex_lock (&self->pv->mutex);
1141 if (self->pv->collections) {
1142 collection = g_hash_table_lookup (self->pv->collections, collection_path);
1143 if (collection != NULL)
1144 g_object_ref (collection);
1146 g_mutex_unlock (&self->pv->mutex);
1152 _secret_service_get_session (SecretService *self)
1154 SecretSession *session;
1156 g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
1158 g_mutex_lock (&self->pv->mutex);
1159 session = self->pv->session;
1160 g_mutex_unlock (&self->pv->mutex);
1166 _secret_service_take_session (SecretService *self,
1167 SecretSession *session)
1169 g_return_if_fail (SECRET_IS_SERVICE (self));
1170 g_return_if_fail (session != NULL);
1172 g_mutex_lock (&self->pv->mutex);
1173 if (self->pv->session == NULL)
1174 self->pv->session = session;
1176 _secret_session_free (session);
1177 g_mutex_unlock (&self->pv->mutex);
1181 * secret_service_get_session_algorithms:
1182 * @self: the secret service proxy
1184 * Get the set of algorithms being used to transfer secrets between this
1185 * secret service proxy and the Secret Service itself.
1187 * This will be %NULL if no session has been established. Use
1188 * secret_service_ensure_session() to establish a session.
1190 * Returns: (allow-none): a string representing the algorithms for transferring
1194 secret_service_get_session_algorithms (SecretService *self)
1196 SecretSession *session;
1197 const gchar *algorithms;
1199 g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
1201 g_mutex_lock (&self->pv->mutex);
1202 session = self->pv->session;
1203 algorithms = session ? _secret_session_get_algorithms (session) : NULL;
1204 g_mutex_unlock (&self->pv->mutex);
1206 /* Session never changes once established, so can return const */
1211 * secret_service_get_session_dbus_path:
1212 * @self: the secret service proxy
1214 * Get the D-Bus object path of the session object being used to transfer
1215 * secrets between this secret service proxy and the Secret Service itself.
1217 * This will be %NULL if no session has been established. Use
1218 * secret_service_ensure_session() to establish a session.
1220 * Returns: (allow-none): a string representing the D-Bus object path of the
1224 secret_service_get_session_dbus_path (SecretService *self)
1226 SecretSession *session;
1229 g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
1231 g_mutex_lock (&self->pv->mutex);
1232 session = self->pv->session;
1233 path = session ? _secret_session_get_path (session) : NULL;
1234 g_mutex_unlock (&self->pv->mutex);
1236 /* Session never changes once established, so can return const */
1241 * secret_service_ensure_session:
1242 * @self: the secret service
1243 * @cancellable: optional cancellation object
1244 * @callback: called when the operation completes
1245 * @user_data: data to be passed to the callback
1247 * Ensure that the #SecretService proxy has established a session with the
1248 * Secret Service. This session is used to transfer secrets.
1250 * It is not normally necessary to call this method, as the session is
1251 * established as necessary. You can also pass the %SECRET_SERVICE_OPEN_SESSION
1252 * to secret_service_get() in order to ensure that a session has been established
1253 * by the time you get the #SecretService proxy.
1255 * This method will return immediately and complete asynchronously.
1258 secret_service_ensure_session (SecretService *self,
1259 GCancellable *cancellable,
1260 GAsyncReadyCallback callback,
1263 GSimpleAsyncResult *res;
1264 SecretSession *session;
1266 g_return_if_fail (SECRET_IS_SERVICE (self));
1267 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1269 g_mutex_lock (&self->pv->mutex);
1270 session = self->pv->session;
1271 g_mutex_unlock (&self->pv->mutex);
1273 if (session == NULL) {
1274 _secret_session_open (self, cancellable, callback, user_data);
1277 res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
1278 secret_service_ensure_session);
1279 g_simple_async_result_complete_in_idle (res);
1280 g_object_unref (res);
1285 * secret_service_ensure_session_finish:
1286 * @self: the secret service
1287 * @result: the asynchronous result passed to the callback
1288 * @error: location to place an error on failure
1290 * Finish an asynchronous operation to ensure that the #SecretService proxy
1291 * has established a session with the Secret Service.
1293 * Returns: whether a session is established or not
1296 secret_service_ensure_session_finish (SecretService *self,
1297 GAsyncResult *result,
1300 g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
1301 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1303 if (!g_simple_async_result_is_valid (result, G_OBJECT (self),
1304 secret_service_ensure_session)) {
1305 if (!_secret_session_open_finish (result, error))
1309 g_return_val_if_fail (self->pv->session != NULL, FALSE);
1314 * secret_service_ensure_session_sync:
1315 * @self: the secret service
1316 * @cancellable: optional cancellation object
1317 * @error: location to place an error on failure
1319 * Ensure that the #SecretService proxy has established a session with the
1320 * Secret Service. This session is used to transfer secrets.
1322 * It is not normally necessary to call this method, as the session is
1323 * established as necessary. You can also pass the %SECRET_SERVICE_OPEN_SESSION
1324 * to secret_service_get_sync() in order to ensure that a session has been
1325 * established by the time you get the #SecretService proxy.
1327 * This method may block indefinitely and should not be used in user interface
1330 * Returns: whether a session is established or not
1333 secret_service_ensure_session_sync (SecretService *self,
1334 GCancellable *cancellable,
1340 g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
1341 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1342 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1344 sync = _secret_sync_new ();
1345 g_main_context_push_thread_default (sync->context);
1347 secret_service_ensure_session (self, cancellable,
1348 _secret_sync_on_result, sync);
1350 g_main_loop_run (sync->loop);
1352 ret = secret_service_ensure_session_finish (self, sync->result, error);
1354 g_main_context_pop_thread_default (sync->context);
1355 _secret_sync_free (sync);
1360 static SecretCollection *
1361 service_lookup_collection (SecretService *self,
1364 SecretCollection *collection = NULL;
1366 g_mutex_lock (&self->pv->mutex);
1368 if (self->pv->collections) {
1369 collection = g_hash_table_lookup (self->pv->collections, path);
1370 if (collection != NULL)
1371 g_object_ref (collection);
1374 g_mutex_unlock (&self->pv->mutex);
1380 service_update_collections (SecretService *self,
1381 GHashTable *collections)
1383 GHashTable *previous;
1385 g_hash_table_ref (collections);
1387 g_mutex_lock (&self->pv->mutex);
1389 previous = self->pv->collections;
1390 self->pv->collections = collections;
1392 g_mutex_unlock (&self->pv->mutex);
1394 if (previous != NULL)
1395 g_hash_table_unref (previous);
1397 g_object_notify (G_OBJECT (self), "collections");
1401 GCancellable *cancellable;
1402 GHashTable *collections;
1403 gint collections_loading;
1407 collections_table_new (void)
1409 return g_hash_table_new_full (g_str_hash, g_str_equal,
1410 g_free, g_object_unref);
1414 ensure_closure_free (gpointer data)
1416 EnsureClosure *closure = data;
1417 g_clear_object (&closure->cancellable);
1418 g_hash_table_unref (closure->collections);
1419 g_slice_free (EnsureClosure, closure);
1423 on_ensure_collection (GObject *source,
1424 GAsyncResult *result,
1427 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1428 SecretService *self = SECRET_SERVICE (g_async_result_get_source_object (user_data));
1429 EnsureClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
1430 SecretCollection *collection;
1432 GError *error = NULL;
1434 closure->collections_loading--;
1436 collection = secret_collection_new_for_dbus_path_finish (result, &error);
1439 g_simple_async_result_take_error (res, error);
1441 if (collection != NULL) {
1442 path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection));
1443 g_hash_table_insert (closure->collections, g_strdup (path), collection);
1446 if (closure->collections_loading == 0) {
1447 service_update_collections (self, closure->collections);
1448 g_simple_async_result_complete (res);
1451 g_object_unref (self);
1452 g_object_unref (res);
1456 * secret_service_load_collections:
1457 * @self: the secret service
1458 * @cancellable: optional cancellation object
1459 * @callback: called when the operation completes
1460 * @user_data: data to be passed to the callback
1462 * Ensure that the #SecretService proxy has loaded all the collections present
1463 * in the Secret Service. This affects the result of
1464 * secret_service_get_collections().
1466 * You can also pass the %SECRET_SERVICE_LOAD_COLLECTIONS to
1467 * secret_service_get_sync() in order to ensure that the collections have been
1468 * loaded by the time you get the #SecretService proxy.
1470 * This method will return immediately and complete asynchronously.
1473 secret_service_load_collections (SecretService *self,
1474 GCancellable *cancellable,
1475 GAsyncReadyCallback callback,
1478 EnsureClosure *closure;
1479 SecretCollection *collection;
1480 GSimpleAsyncResult *res;
1485 g_return_if_fail (SECRET_IS_SERVICE (self));
1486 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1488 paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Collections");
1489 g_return_if_fail (paths != NULL);
1491 res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
1492 secret_service_load_collections);
1493 closure = g_slice_new0 (EnsureClosure);
1494 closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
1495 closure->collections = collections_table_new ();
1496 g_simple_async_result_set_op_res_gpointer (res, closure, ensure_closure_free);
1498 g_variant_iter_init (&iter, paths);
1499 while (g_variant_iter_loop (&iter, "&o", &path)) {
1500 collection = service_lookup_collection (self, path);
1502 /* No such collection yet create a new one */
1503 if (collection == NULL) {
1504 secret_collection_new_for_dbus_path (self, path, SECRET_COLLECTION_LOAD_ITEMS,
1505 cancellable, on_ensure_collection, g_object_ref (res));
1506 closure->collections_loading++;
1508 g_hash_table_insert (closure->collections, g_strdup (path), collection);
1512 if (closure->collections_loading == 0) {
1513 service_update_collections (self, closure->collections);
1514 g_simple_async_result_complete_in_idle (res);
1517 g_variant_unref (paths);
1518 g_object_unref (res);
1522 * secret_service_load_collections_finish:
1523 * @self: the secret service
1524 * @result: the asynchronous result passed to the callback
1525 * @error: location to place an error on failure
1527 * Complete an asynchronous operation to ensure that the #SecretService proxy
1528 * has loaded all the collections present in the Secret Service.
1530 * Returns: whether the load was successful or not
1533 secret_service_load_collections_finish (SecretService *self,
1534 GAsyncResult *result,
1537 g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
1538 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1539 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
1540 secret_service_load_collections), FALSE);
1542 if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
1549 * secret_service_load_collections_sync:
1550 * @self: the secret service
1551 * @cancellable: optional cancellation object
1552 * @error: location to place an error on failure
1554 * Ensure that the #SecretService proxy has loaded all the collections present
1555 * in the Secret Service. This affects the result of
1556 * secret_service_get_collections().
1558 * You can also pass the %SECRET_SERVICE_LOAD_COLLECTIONS to
1559 * secret_service_get_sync() in order to ensure that the collections have been
1560 * loaded by the time you get the #SecretService proxy.
1562 * This method may block indefinitely and should not be used in user interface
1565 * Returns: whether the load was successful or not
1568 secret_service_load_collections_sync (SecretService *self,
1569 GCancellable *cancellable,
1572 SecretCollection *collection;
1573 GHashTable *collections;
1577 gboolean ret = TRUE;
1579 g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
1580 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1581 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1583 paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Collections");
1584 g_return_val_if_fail (paths != NULL, FALSE);
1586 collections = collections_table_new ();
1588 g_variant_iter_init (&iter, paths);
1589 while (g_variant_iter_next (&iter, "&o", &path)) {
1590 collection = service_lookup_collection (self, path);
1592 /* No such collection yet create a new one */
1593 if (collection == NULL) {
1594 collection = secret_collection_new_for_dbus_path_sync (self, path,
1595 SECRET_COLLECTION_LOAD_ITEMS,
1596 cancellable, error);
1597 if (collection == NULL) {
1603 g_hash_table_insert (collections, g_strdup (path), collection);
1607 service_update_collections (self, collections);
1609 g_hash_table_unref (collections);
1610 g_variant_unref (paths);
1615 * secret_service_prompt_sync:
1616 * @self: the secret service
1617 * @prompt: the prompt
1618 * @cancellable: optional cancellation object
1619 * @return_type: the variant type of the prompt result
1620 * @error: location to place an error on failure
1622 * Perform prompting for a #SecretPrompt.
1624 * Runs a prompt and performs the prompting. Returns a variant result if the
1625 * prompt was completed and not dismissed. The type of result depends on the
1626 * action the prompt is completing, and is defined in the Secret Service DBus
1627 * API specification.
1629 * This function is called by other parts of this library to handle prompts
1630 * for the various actions that can require prompting.
1632 * Override the #SecretServiceClass <literal>prompt_sync</literal> virtual method
1633 * to change the behavior of the propmting. The default behavior is to simply
1634 * run secret_prompt_perform_sync() on the prompt.
1636 * Returns: (transfer full): %NULL if the prompt was dismissed or an error occurred,
1637 * a variant result if the prompt was successful
1640 secret_service_prompt_sync (SecretService *self,
1641 SecretPrompt *prompt,
1642 GCancellable *cancellable,
1643 const GVariantType *return_type,
1646 SecretServiceClass *klass;
1648 g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
1649 g_return_val_if_fail (SECRET_IS_PROMPT (prompt), NULL);
1650 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
1651 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1653 klass = SECRET_SERVICE_GET_CLASS (self);
1654 g_return_val_if_fail (klass->prompt_sync != NULL, NULL);
1656 return (klass->prompt_sync) (self, prompt, cancellable, return_type, error);
1660 * secret_service_prompt:
1661 * @self: the secret service
1662 * @prompt: the prompt
1663 * @cancellable: optional cancellation object
1664 * @callback: called when the operation completes
1665 * @user_data: data to be passed to the callback
1667 * Perform prompting for a #SecretPrompt.
1669 * This function is called by other parts of this library to handle prompts
1670 * for the various actions that can require prompting.
1672 * Override the #SecretServiceClass <literal>prompt_async</literal> virtual method
1673 * to change the behavior of the propmting. The default behavior is to simply
1674 * run secret_prompt_perform() on the prompt.
1677 secret_service_prompt (SecretService *self,
1678 SecretPrompt *prompt,
1679 GCancellable *cancellable,
1680 GAsyncReadyCallback callback,
1683 SecretServiceClass *klass;
1685 g_return_if_fail (SECRET_IS_SERVICE (self));
1686 g_return_if_fail (SECRET_IS_PROMPT (prompt));
1687 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1689 klass = SECRET_SERVICE_GET_CLASS (self);
1690 g_return_if_fail (klass->prompt_async != NULL);
1692 (klass->prompt_async) (self, prompt, cancellable, callback, user_data);
1696 * secret_service_prompt_finish:
1697 * @self: the secret service
1698 * @result: the asynchronous result passed to the callback
1699 * @return_type: the variant type of the prompt result
1700 * @error: location to place an error on failure
1702 * Complete asynchronous operation to perform prompting for a #SecretPrompt.
1704 * Returns a variant result if the prompt was completed and not dismissed. The
1705 * type of result depends on the action the prompt is completing, and is defined
1706 * in the Secret Service DBus API specification.
1708 * Returns: (transfer full): %NULL if the prompt was dismissed or an error occurred,
1709 * a variant result if the prompt was successful
1712 secret_service_prompt_finish (SecretService *self,
1713 GAsyncResult *result,
1714 const GVariantType *return_type,
1717 SecretServiceClass *klass;
1719 g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
1720 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
1721 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1723 klass = SECRET_SERVICE_GET_CLASS (self);
1724 g_return_val_if_fail (klass->prompt_finish != NULL, NULL);
1726 return (klass->prompt_finish) (self, result, return_type, error);