1 /* libsecret - GLib wrapper for Secret Service
2 *
3 * Copyright 2011 Collabora Ltd.
4 * Copyright 2012 Red Hat Inc.
5 *
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.
10 *
11 * See the included COPYING file for more information.
12 *
13 * Author: Stef Walter <stefw@gnome.org>
14 */
15
16 #include "config.h"
17
18 #include "secret-collection.h"
19 #include "secret-dbus-generated.h"
20 #include "secret-item.h"
21 #include "secret-paths.h"
22 #include "secret-private.h"
23 #include "secret-service.h"
24 #include "secret-types.h"
25 #include "secret-value.h"
26
27 #include <glib/gi18n-lib.h>
28
29 /**
30 * SecretSearchFlags:
31 * @SECRET_SEARCH_NONE: no flags
32 * @SECRET_SEARCH_ALL: all the items matching the search will be returned, instead of just the first one
33 * @SECRET_SEARCH_UNLOCK: unlock locked items while searching
34 * @SECRET_SEARCH_LOAD_SECRETS: while searching load secrets for items that are not locked
35 *
36 * Various flags to be used with secret_service_search() and secret_service_search_sync().
37 */
38
39 typedef struct {
40 SecretService *service;
41 GCancellable *cancellable;
42 GHashTable *items;
43 gchar **unlocked;
44 gchar **locked;
45 guint loading;
46 SecretSearchFlags flags;
47 GVariant *attributes;
48 } SearchClosure;
49
50 static void
search_closure_free(gpointer data)51 search_closure_free (gpointer data)
52 {
53 SearchClosure *closure = data;
54 g_clear_object (&closure->service);
55 g_clear_object (&closure->cancellable);
56 g_hash_table_unref (closure->items);
57 g_variant_unref (closure->attributes);
58 g_strfreev (closure->unlocked);
59 g_strfreev (closure->locked);
60 g_slice_free (SearchClosure, closure);
61 }
62
63 static void
search_closure_take_item(SearchClosure * closure,SecretItem * item)64 search_closure_take_item (SearchClosure *closure,
65 SecretItem *item)
66 {
67 const gchar *path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (item));
68 g_hash_table_insert (closure->items, (gpointer)path, item);
69 }
70
71 static GList *
search_closure_build_items(SearchClosure * closure,gchar ** paths)72 search_closure_build_items (SearchClosure *closure,
73 gchar **paths)
74 {
75 GList *results = NULL;
76 SecretItem *item;
77 guint i;
78
79 for (i = 0; paths[i]; i++) {
80 item = g_hash_table_lookup (closure->items, paths[i]);
81 if (item != NULL)
82 results = g_list_prepend (results, g_object_ref (item));
83 }
84
85 return g_list_reverse (results);
86 }
87
88 static void
on_search_secrets(GObject * source,GAsyncResult * result,gpointer user_data)89 on_search_secrets (GObject *source,
90 GAsyncResult *result,
91 gpointer user_data)
92 {
93 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
94
95 /* Note that we ignore any unlock failure */
96 secret_item_load_secrets_finish (result, NULL);
97
98 g_simple_async_result_complete (async);
99 g_object_unref (async);
100 }
101
102 static void
on_search_unlocked(GObject * source,GAsyncResult * result,gpointer user_data)103 on_search_unlocked (GObject *source,
104 GAsyncResult *result,
105 gpointer user_data)
106 {
107 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
108 SearchClosure *search = g_simple_async_result_get_op_res_gpointer (async);
109 GList *items;
110
111 /* Note that we ignore any unlock failure */
112 secret_service_unlock_finish (search->service, result, NULL, NULL);
113
114 /* If loading secrets ... locked items automatically ignored */
115 if (search->flags & SECRET_SEARCH_LOAD_SECRETS) {
116 items = g_hash_table_get_values (search->items);
117 secret_item_load_secrets (items, search->cancellable,
118 on_search_secrets, g_object_ref (async));
119 g_list_free (items);
120
121 /* No additional options, just complete */
122 } else {
123 g_simple_async_result_complete (async);
124 }
125
126 g_object_unref (async);
127 }
128
129 static void
secret_search_unlock_load_or_complete(GSimpleAsyncResult * async,SearchClosure * search)130 secret_search_unlock_load_or_complete (GSimpleAsyncResult *async,
131 SearchClosure *search)
132 {
133 GList *items;
134
135 /* If unlocking then unlock all the locked items */
136 if (search->flags & SECRET_SEARCH_UNLOCK) {
137 items = search_closure_build_items (search, search->locked);
138 secret_service_unlock (search->service, items, search->cancellable,
139 on_search_unlocked, g_object_ref (async));
140 g_list_free_full (items, g_object_unref);
141
142 /* If loading secrets ... locked items automatically ignored */
143 } else if (search->flags & SECRET_SEARCH_LOAD_SECRETS) {
144 items = g_hash_table_get_values (search->items);
145 secret_item_load_secrets (items, search->cancellable,
146 on_search_secrets, g_object_ref (async));
147 g_list_free (items);
148
149 /* No additional options, just complete */
150 } else {
151 g_simple_async_result_complete (async);
152 }
153 }
154
155 static void
on_search_loaded(GObject * source,GAsyncResult * result,gpointer user_data)156 on_search_loaded (GObject *source,
157 GAsyncResult *result,
158 gpointer user_data)
159 {
160 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
161 SearchClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
162 GError *error = NULL;
163 SecretItem *item;
164
165 closure->loading--;
166
167 item = secret_item_new_for_dbus_path_finish (result, &error);
168 if (error != NULL)
169 g_simple_async_result_take_error (res, error);
170
171 if (item != NULL)
172 search_closure_take_item (closure, item);
173
174 /* We're done loading, lets go to the next step */
175 if (closure->loading == 0)
176 secret_search_unlock_load_or_complete (res, closure);
177
178 g_object_unref (res);
179 }
180
181 static void
search_load_item_async(SecretService * self,GSimpleAsyncResult * res,SearchClosure * closure,const gchar * path)182 search_load_item_async (SecretService *self,
183 GSimpleAsyncResult *res,
184 SearchClosure *closure,
185 const gchar *path)
186 {
187 SecretItem *item;
188
189 item = _secret_service_find_item_instance (self, path);
190 if (item == NULL) {
191 secret_item_new_for_dbus_path (self, path, SECRET_ITEM_NONE, closure->cancellable,
192 on_search_loaded, g_object_ref (res));
193 closure->loading++;
194 } else {
195 search_closure_take_item (closure, item);
196 }
197 }
198
199 static void
on_search_paths(GObject * source,GAsyncResult * result,gpointer user_data)200 on_search_paths (GObject *source,
201 GAsyncResult *result,
202 gpointer user_data)
203 {
204 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
205 SearchClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
206 SecretService *self = closure->service;
207 GError *error = NULL;
208 gint want = 1;
209 gint count;
210 gint i;
211
212 secret_service_search_for_dbus_paths_finish (self, result, &closure->unlocked,
213 &closure->locked, &error);
214 if (error == NULL) {
215 want = 1;
216 if (closure->flags & SECRET_SEARCH_ALL)
217 want = G_MAXINT;
218 count = 0;
219
220 for (i = 0; count < want && closure->unlocked[i] != NULL; i++, count++)
221 search_load_item_async (self, res, closure, closure->unlocked[i]);
222 for (i = 0; count < want && closure->locked[i] != NULL; i++, count++)
223 search_load_item_async (self, res, closure, closure->locked[i]);
224
225 /* No items loading, complete operation now */
226 if (closure->loading == 0)
227 secret_search_unlock_load_or_complete (res, closure);
228
229 } else {
230 g_simple_async_result_take_error (res, error);
231 g_simple_async_result_complete (res);
232 }
233
234 g_object_unref (res);
235 }
236
237 static void
on_search_service(GObject * source,GAsyncResult * result,gpointer user_data)238 on_search_service (GObject *source,
239 GAsyncResult *result,
240 gpointer user_data)
241 {
242 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
243 SearchClosure *search = g_simple_async_result_get_op_res_gpointer (async);
244 GError *error = NULL;
245
246 search->service = secret_service_get_finish (result, &error);
247 if (error == NULL) {
248 _secret_service_search_for_paths_variant (search->service, search->attributes,
249 search->cancellable, on_search_paths,
250 g_object_ref (async));
251
252 } else {
253 g_simple_async_result_take_error (async, error);
254 g_simple_async_result_complete (async);
255 }
256
257 g_object_unref (async);
258 }
259
260 /**
261 * secret_service_search:
262 * @service: (allow-none): the secret service
263 * @schema: (allow-none): the schema for the attributes
264 * @attributes: (element-type utf8 utf8): search for items matching these attributes
265 * @flags: search option flags
266 * @cancellable: optional cancellation object
267 * @callback: called when the operation completes
268 * @user_data: data to pass to the callback
269 *
270 * Search for items matching the @attributes. All collections are searched.
271 * The @attributes should be a table of string keys and string values.
272 *
273 * If @service is NULL, then secret_service_get() will be called to get
274 * the default #SecretService proxy.
275 *
276 * If %SECRET_SEARCH_ALL is set in @flags, then all the items matching the
277 * search will be returned. Otherwise only the first item will be returned.
278 * This is almost always the unlocked item that was most recently stored.
279 *
280 * If %SECRET_SEARCH_UNLOCK is set in @flags, then items will be unlocked
281 * if necessary. In either case, locked and unlocked items will match the
282 * search and be returned. If the unlock fails, the search does not fail.
283 *
284 * If %SECRET_SEARCH_LOAD_SECRETS is set in @flags, then the items will have
285 * their secret values loaded and available via secret_item_get_secret().
286 *
287 * This function returns immediately and completes asynchronously.
288 */
289 void
secret_service_search(SecretService * service,const SecretSchema * schema,GHashTable * attributes,SecretSearchFlags flags,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)290 secret_service_search (SecretService *service,
291 const SecretSchema *schema,
292 GHashTable *attributes,
293 SecretSearchFlags flags,
294 GCancellable *cancellable,
295 GAsyncReadyCallback callback,
296 gpointer user_data)
297 {
298 GSimpleAsyncResult *res;
299 SearchClosure *closure;
300 const gchar *schema_name = NULL;
301
302 g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service));
303 g_return_if_fail (attributes != NULL);
304 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
305
306 /* Warnings raised already */
307 if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
308 return;
309
310 if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME))
311 schema_name = schema->name;
312
313 res = g_simple_async_result_new (G_OBJECT (service), callback, user_data,
314 secret_service_search);
315 closure = g_slice_new0 (SearchClosure);
316 closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
317 closure->items = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
318 closure->flags = flags;
319 closure->attributes = _secret_attributes_to_variant (attributes, schema_name);
320 g_variant_ref_sink (closure->attributes);
321 g_simple_async_result_set_op_res_gpointer (res, closure, search_closure_free);
322
323 if (service) {
324 closure->service = g_object_ref (service);
325 _secret_service_search_for_paths_variant (closure->service, closure->attributes,
326 closure->cancellable, on_search_paths,
327 g_object_ref (res));
328
329 } else {
330 secret_service_get (SECRET_SERVICE_NONE, cancellable,
331 on_search_service, g_object_ref (res));
332 }
333
334 g_object_unref (res);
335 }
336
337 /**
338 * secret_service_search_finish:
339 * @service: (allow-none): the secret service
340 * @result: asynchronous result passed to callback
341 * @error: location to place error on failure
342 *
343 * Complete asynchronous operation to search for items.
344 *
345 * Returns: (transfer full) (element-type Secret.Item):
346 * a list of items that matched the search
347 */
348 GList *
secret_service_search_finish(SecretService * service,GAsyncResult * result,GError ** error)349 secret_service_search_finish (SecretService *service,
350 GAsyncResult *result,
351 GError **error)
352 {
353 GSimpleAsyncResult *res;
354 SearchClosure *closure;
355 GList *items = NULL;
356
357 g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL);
358 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
359 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (service),
360 secret_service_search), NULL);
361
362 res = G_SIMPLE_ASYNC_RESULT (result);
363
364 if (_secret_util_propagate_error (res, error))
365 return NULL;
366
367 closure = g_simple_async_result_get_op_res_gpointer (res);
368 if (closure->unlocked)
369 items = search_closure_build_items (closure, closure->unlocked);
370 if (closure->locked)
371 items = g_list_concat (items, search_closure_build_items (closure, closure->locked));
372 return items;
373 }
374
375 static gboolean
service_load_items_sync(SecretService * service,GCancellable * cancellable,gchar ** paths,GList ** items,gint want,gint * have,GError ** error)376 service_load_items_sync (SecretService *service,
377 GCancellable *cancellable,
378 gchar **paths,
379 GList **items,
380 gint want,
381 gint *have,
382 GError **error)
383 {
384 SecretItem *item;
385 guint i;
386
387 for (i = 0; *have < want && paths[i] != NULL; i++) {
388 item = _secret_service_find_item_instance (service, paths[i]);
389 if (item == NULL)
390 item = secret_item_new_for_dbus_path_sync (service, paths[i], SECRET_ITEM_NONE,
391 cancellable, error);
392 if (item == NULL) {
393 return FALSE;
394
395 } else {
396 *items = g_list_prepend (*items, item);
397 (*have)++;
398 }
399 }
400
401 return TRUE;
402 }
403
404 /**
405 * secret_service_search_sync:
406 * @service: (allow-none): the secret service
407 * @schema: (allow-none): the schema for the attributes
408 * @attributes: (element-type utf8 utf8): search for items matching these attributes
409 * @flags: search option flags
410 * @cancellable: optional cancellation object
411 * @error: location to place error on failure
412 *
413 * Search for items matching the @attributes. All collections are searched.
414 * The @attributes should be a table of string keys and string values.
415 *
416 * If @service is NULL, then secret_service_get_sync() will be called to get
417 * the default #SecretService proxy.
418 *
419 * If %SECRET_SEARCH_ALL is set in @flags, then all the items matching the
420 * search will be returned. Otherwise only the first item will be returned.
421 * This is almost always the unlocked item that was most recently stored.
422 *
423 * If %SECRET_SEARCH_UNLOCK is set in @flags, then items will be unlocked
424 * if necessary. In either case, locked and unlocked items will match the
425 * search and be returned. If the unlock fails, the search does not fail.
426 *
427 * If %SECRET_SEARCH_LOAD_SECRETS is set in @flags, then the items' secret
428 * values will be loaded for any unlocked items. Loaded item secret values
429 * are available via secret_item_get_secret(). If the load of a secret values
430 * fail, then the
431 *
432 * This function may block indefinitely. Use the asynchronous version
433 * in user interface threads.
434 *
435 * Returns: (transfer full) (element-type Secret.Item):
436 * a list of items that matched the search
437 */
438 GList *
secret_service_search_sync(SecretService * service,const SecretSchema * schema,GHashTable * attributes,SecretSearchFlags flags,GCancellable * cancellable,GError ** error)439 secret_service_search_sync (SecretService *service,
440 const SecretSchema *schema,
441 GHashTable *attributes,
442 SecretSearchFlags flags,
443 GCancellable *cancellable,
444 GError **error)
445 {
446 gchar **unlocked_paths = NULL;
447 gchar **locked_paths = NULL;
448 GList *items = NULL;
449 GList *locked = NULL;
450 GList *unlocked = NULL;
451 gboolean ret;
452 gint want;
453 gint have;
454
455 g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL);
456 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
457 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
458
459 /* Warnings raised already */
460 if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
461 return NULL;
462
463 if (service == NULL) {
464 service = secret_service_get_sync (SECRET_SERVICE_NONE, cancellable, error);
465 if (service == NULL)
466 return NULL;
467 } else {
468 g_object_ref (service);
469 }
470
471 if (!secret_service_search_for_dbus_paths_sync (service, schema, attributes, cancellable,
472 &unlocked_paths, &locked_paths, error)) {
473 g_object_unref (service);
474 return NULL;
475 }
476
477 ret = TRUE;
478
479 want = 1;
480 if (flags & SECRET_SEARCH_ALL)
481 want = G_MAXINT;
482 have = 0;
483
484 /* Remember, we're adding to the list backwards */
485
486 if (unlocked_paths) {
487 ret = service_load_items_sync (service, cancellable, unlocked_paths,
488 &unlocked, want, &have, error);
489 }
490
491 if (ret && locked_paths) {
492 ret = service_load_items_sync (service, cancellable, locked_paths,
493 &locked, want, &have, error);
494 }
495
496 g_strfreev (unlocked_paths);
497 g_strfreev (locked_paths);
498
499 if (!ret) {
500 g_list_free_full (unlocked, g_object_unref);
501 g_list_free_full (locked, g_object_unref);
502 g_object_unref (service);
503 return NULL;
504 }
505
506 /* The lists are backwards at this point ... */
507 items = g_list_concat (items, g_list_copy (locked));
508 items = g_list_concat (items, g_list_copy (unlocked));
509 items = g_list_reverse (items);
510
511 if (flags & SECRET_SEARCH_UNLOCK)
512 secret_service_unlock_sync (service, locked, cancellable, NULL, NULL);
513
514 if (flags & SECRET_SEARCH_LOAD_SECRETS)
515 secret_item_load_secrets_sync (items, NULL, NULL);
516
517 g_list_free (locked);
518 g_list_free (unlocked);
519 g_object_unref (service);
520 return items;
521 }
522
523 SecretValue *
_secret_service_decode_get_secrets_first(SecretService * self,GVariant * out)524 _secret_service_decode_get_secrets_first (SecretService *self,
525 GVariant *out)
526 {
527 SecretSession *session;
528 SecretValue *value = NULL;
529 GVariantIter *iter;
530 GVariant *variant;
531 const gchar *path;
532
533 g_variant_get (out, "(a{o(oayays)})", &iter);
534 while (g_variant_iter_next (iter, "{&o@(oayays)}", &path, &variant)) {
535 session = _secret_service_get_session (self);
536 value = _secret_session_decode_secret (session, variant);
537 g_variant_unref (variant);
538 break;
539 }
540 g_variant_iter_free (iter);
541 return value;
542 }
543
544 GHashTable *
_secret_service_decode_get_secrets_all(SecretService * self,GVariant * out)545 _secret_service_decode_get_secrets_all (SecretService *self,
546 GVariant *out)
547 {
548 SecretSession *session;
549 GVariantIter *iter;
550 GVariant *variant;
551 GHashTable *values;
552 SecretValue *value;
553 gchar *path;
554
555 session = _secret_service_get_session (self);
556 values = g_hash_table_new_full (g_str_hash, g_str_equal,
557 g_free, secret_value_unref);
558 g_variant_get (out, "(a{o(oayays)})", &iter);
559 while (g_variant_iter_loop (iter, "{o@(oayays)}", &path, &variant)) {
560 value = _secret_session_decode_secret (session, variant);
561 if (value && path)
562 g_hash_table_insert (values, g_strdup (path), value);
563 }
564 g_variant_iter_free (iter);
565 return values;
566 }
567
568 typedef struct {
569 GCancellable *cancellable;
570 GPtrArray *paths;
571 GHashTable *objects;
572 gchar **xlocked;
573 guint count;
574 gboolean locking;
575 } XlockClosure;
576
577 static void
xlock_closure_free(gpointer data)578 xlock_closure_free (gpointer data)
579 {
580 XlockClosure *closure = data;
581 if (closure->cancellable)
582 g_object_unref (closure->cancellable);
583 g_ptr_array_free (closure->paths, TRUE);
584 g_strfreev (closure->xlocked);
585 g_hash_table_unref (closure->objects);
586 g_slice_free (XlockClosure, closure);
587 }
588
589 static void
on_xlock_paths(GObject * source,GAsyncResult * result,gpointer user_data)590 on_xlock_paths (GObject *source,
591 GAsyncResult *result,
592 gpointer user_data)
593 {
594 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
595 XlockClosure *xlock = g_simple_async_result_get_op_res_gpointer (async);
596 GVariant *lockval;
597 GDBusProxy *object;
598 GError *error = NULL;
599 gint i;
600
601 xlock->count = _secret_service_xlock_paths_finish (SECRET_SERVICE (source), result,
602 &xlock->xlocked, &error);
603
604 if (error == NULL) {
605 /*
606 * After a lock or unlock we want the Locked property to immediately
607 * reflect the new state, and not have to wait for a PropertiesChanged
608 * signal to be processed later.
609 */
610
611 lockval = g_variant_ref_sink (g_variant_new_boolean (xlock->locking));
612 for (i = 0; xlock->xlocked[i] != NULL; i++) {
613 object = g_hash_table_lookup (xlock->objects, xlock->xlocked[i]);
614 if (object != NULL)
615 g_dbus_proxy_set_cached_property (object, "Locked", lockval);
616 }
617 g_variant_unref (lockval);
618
619 } else {
620 g_simple_async_result_take_error (async, error);
621 }
622
623 g_simple_async_result_complete (async);
624 g_object_unref (async);
625 }
626
627 static void
on_xlock_service(GObject * source,GAsyncResult * result,gpointer user_data)628 on_xlock_service (GObject *source,
629 GAsyncResult *result,
630 gpointer user_data)
631 {
632 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
633 XlockClosure *xlock = g_simple_async_result_get_op_res_gpointer (async);
634 GError *error = NULL;
635 SecretService *service;
636
637 service = secret_service_get_finish (result, &error);
638 if (error == NULL) {
639 _secret_service_xlock_paths_async (service, xlock->locking ? "Lock" : "Unlock",
640 (const gchar **)xlock->paths->pdata,
641 xlock->cancellable, on_xlock_paths,
642 g_object_ref (async));
643 g_object_unref (service);
644
645 } else {
646 g_simple_async_result_take_error (async, error);
647 g_simple_async_result_complete (async);
648 }
649
650 g_object_unref (async);
651 }
652
653 static void
service_xlock_async(SecretService * service,gboolean locking,GList * objects,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)654 service_xlock_async (SecretService *service,
655 gboolean locking,
656 GList *objects,
657 GCancellable *cancellable,
658 GAsyncReadyCallback callback,
659 gpointer user_data)
660 {
661 GSimpleAsyncResult *async;
662 XlockClosure *xlock;
663 const gchar *path;
664 GList *l;
665
666 async = g_simple_async_result_new (G_OBJECT (service), callback, user_data,
667 service_xlock_async);
668 xlock = g_slice_new0 (XlockClosure);
669 xlock->objects = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
670 xlock->locking = locking;
671 xlock->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
672 xlock->paths = g_ptr_array_new ();
673
674 for (l = objects; l != NULL; l = g_list_next (l)) {
675 path = g_dbus_proxy_get_object_path (l->data);
676 g_ptr_array_add (xlock->paths, (gpointer)path);
677 g_hash_table_insert (xlock->objects, g_strdup (path), g_object_ref (l->data));
678 }
679 g_ptr_array_add (xlock->paths, NULL);
680
681 g_simple_async_result_set_op_res_gpointer (async, xlock, xlock_closure_free);
682
683 if (service == NULL) {
684 secret_service_get (SECRET_SERVICE_NONE, cancellable,
685 on_xlock_service, g_object_ref (async));
686 } else {
687 _secret_service_xlock_paths_async (service, xlock->locking ? "Lock" : "Unlock",
688 (const gchar **)xlock->paths->pdata,
689 xlock->cancellable, on_xlock_paths,
690 g_object_ref (async));
691 }
692
693 g_object_unref (async);
694 }
695
696 static gint
service_xlock_finish(SecretService * service,GAsyncResult * result,GList ** xlocked,GError ** error)697 service_xlock_finish (SecretService *service,
698 GAsyncResult *result,
699 GList **xlocked,
700 GError **error)
701 {
702 GSimpleAsyncResult *async;
703 XlockClosure *xlock;
704 GDBusProxy *object;
705 gint i;
706
707 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (service),
708 service_xlock_async), -1);
709
710 async = G_SIMPLE_ASYNC_RESULT (result);
711 if (_secret_util_propagate_error (async, error))
712 return -1;
713
714 xlock = g_simple_async_result_get_op_res_gpointer (async);
715 if (xlocked) {
716 *xlocked = NULL;
717 for (i = 0; xlock->xlocked[i] != NULL; i++) {
718 object = g_hash_table_lookup (xlock->objects, xlock->xlocked[i]);
719 if (object != NULL)
720 *xlocked = g_list_prepend (*xlocked, g_object_ref (object));
721 }
722 }
723
724 return xlock->count;
725 }
726
727 /**
728 * secret_service_lock:
729 * @service: (allow-none): the secret service
730 * @objects: (element-type Gio.DBusProxy): the items or collections to lock
731 * @cancellable: optional cancellation object
732 * @callback: called when the operation completes
733 * @user_data: data to pass to the callback
734 *
735 * Lock items or collections in the secret service.
736 *
737 * The secret service may not be able to lock items individually, and may
738 * lock an entire collection instead.
739 *
740 * If @service is NULL, then secret_service_get() will be called to get
741 * the default #SecretService proxy.
742 *
743 * This method returns immediately and completes asynchronously. The secret
744 * service may prompt the user. secret_service_prompt() will be used to handle
745 * any prompts that show up.
746 */
747 void
secret_service_lock(SecretService * service,GList * objects,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)748 secret_service_lock (SecretService *service,
749 GList *objects,
750 GCancellable *cancellable,
751 GAsyncReadyCallback callback,
752 gpointer user_data)
753 {
754 g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service));
755 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
756
757 service_xlock_async (service, TRUE, objects, cancellable, callback, user_data);
758 }
759
760 /**
761 * secret_service_lock_finish:
762 * @service: (allow-none): the secret service
763 * @result: asynchronous result passed to the callback
764 * @locked: (out) (element-type Gio.DBusProxy) (transfer full) (allow-none):
765 * location to place list of items or collections that were locked
766 * @error: location to place an error on failure
767 *
768 * Complete asynchronous operation to lock items or collections in the secret
769 * service.
770 *
771 * The secret service may not be able to lock items individually, and may
772 * lock an entire collection instead.
773 *
774 * Returns: the number of items or collections that were locked
775 */
776 gint
secret_service_lock_finish(SecretService * service,GAsyncResult * result,GList ** locked,GError ** error)777 secret_service_lock_finish (SecretService *service,
778 GAsyncResult *result,
779 GList **locked,
780 GError **error)
781 {
782 g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), -1);
783 g_return_val_if_fail (error == NULL || *error == NULL, -1);
784
785 return service_xlock_finish (service, result, locked, error);
786 }
787
788 /**
789 * secret_service_lock_sync:
790 * @service: (allow-none): the secret service
791 * @objects: (element-type Gio.DBusProxy): the items or collections to lock
792 * @cancellable: optional cancellation object
793 * @locked: (out) (element-type Gio.DBusProxy) (transfer full) (allow-none):
794 * location to place list of items or collections that were locked
795 * @error: location to place an error on failure
796 *
797 * Lock items or collections in the secret service.
798 *
799 * The secret service may not be able to lock items individually, and may
800 * lock an entire collection instead.
801 *
802 * If @service is NULL, then secret_service_get_sync() will be called to get
803 * the default #SecretService proxy.
804 *
805 * This method may block indefinitely and should not be used in user
806 * interface threads. The secret service may prompt the user.
807 * secret_service_prompt() will be used to handle any prompts that show up.
808 *
809 * Returns: the number of items or collections that were locked
810 */
811 gint
secret_service_lock_sync(SecretService * service,GList * objects,GCancellable * cancellable,GList ** locked,GError ** error)812 secret_service_lock_sync (SecretService *service,
813 GList *objects,
814 GCancellable *cancellable,
815 GList **locked,
816 GError **error)
817 {
818 SecretSync *sync;
819 gint count;
820
821 g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), -1);
822 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1);
823 g_return_val_if_fail (error == NULL || *error == NULL, -1);
824
825 sync = _secret_sync_new ();
826 g_main_context_push_thread_default (sync->context);
827
828 secret_service_lock (service, objects, cancellable,
829 _secret_sync_on_result, sync);
830
831 g_main_loop_run (sync->loop);
832
833 count = secret_service_lock_finish (service, sync->result, locked, error);
834
835 g_main_context_pop_thread_default (sync->context);
836 _secret_sync_free (sync);
837
838 return count;
839 }
840
841 /**
842 * secret_service_unlock:
843 * @service: (allow-none): the secret service
844 * @objects: (element-type Gio.DBusProxy): the items or collections to unlock
845 * @cancellable: optional cancellation object
846 * @callback: called when the operation completes
847 * @user_data: data to pass to the callback
848 *
849 * Unlock items or collections in the secret service.
850 *
851 * The secret service may not be able to unlock items individually, and may
852 * unlock an entire collection instead.
853 *
854 * If @service is NULL, then secret_service_get() will be called to get
855 * the default #SecretService proxy.
856 *
857 * This method may block indefinitely and should not be used in user
858 * interface threads. The secret service may prompt the user.
859 * secret_service_prompt() will be used to handle any prompts that show up.
860 */
861 void
secret_service_unlock(SecretService * service,GList * objects,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)862 secret_service_unlock (SecretService *service,
863 GList *objects,
864 GCancellable *cancellable,
865 GAsyncReadyCallback callback,
866 gpointer user_data)
867 {
868 g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service));
869 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
870
871 service_xlock_async (service, FALSE, objects, cancellable, callback, user_data);
872 }
873
874 /**
875 * secret_service_unlock_finish:
876 * @service: (allow-none): the secret service
877 * @result: asynchronous result passed to the callback
878 * @unlocked: (out) (element-type Gio.DBusProxy) (transfer full) (allow-none):
879 * location to place list of items or collections that were unlocked
880 * @error: location to place an error on failure
881 *
882 * Complete asynchronous operation to unlock items or collections in the secret
883 * service.
884 *
885 * The secret service may not be able to unlock items individually, and may
886 * unlock an entire collection instead.
887 *
888 * Returns: the number of items or collections that were unlocked
889 */
890 gint
secret_service_unlock_finish(SecretService * service,GAsyncResult * result,GList ** unlocked,GError ** error)891 secret_service_unlock_finish (SecretService *service,
892 GAsyncResult *result,
893 GList **unlocked,
894 GError **error)
895 {
896 g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), -1);
897 g_return_val_if_fail (error == NULL || *error == NULL, -1);
898
899 return service_xlock_finish (service, result, unlocked, error);
900 }
901
902 /**
903 * secret_service_unlock_sync:
904 * @service: (allow-none): the secret service
905 * @objects: (element-type Gio.DBusProxy): the items or collections to unlock
906 * @cancellable: optional cancellation object
907 * @unlocked: (out) (element-type Gio.DBusProxy) (transfer full) (allow-none):
908 * location to place list of items or collections that were unlocked
909 * @error: location to place an error on failure
910 *
911 * Unlock items or collections in the secret service.
912 *
913 * The secret service may not be able to unlock items individually, and may
914 * unlock an entire collection instead.
915 *
916 * If @service is NULL, then secret_service_get_sync() will be called to get
917 * the default #SecretService proxy.
918 *
919 * This method may block indefinitely and should not be used in user
920 * interface threads. The secret service may prompt the user.
921 * secret_service_prompt() will be used to handle any prompts that show up.
922 *
923 * Returns: the number of items or collections that were unlocked
924 */
925 gint
secret_service_unlock_sync(SecretService * service,GList * objects,GCancellable * cancellable,GList ** unlocked,GError ** error)926 secret_service_unlock_sync (SecretService *service,
927 GList *objects,
928 GCancellable *cancellable,
929 GList **unlocked,
930 GError **error)
931 {
932 SecretSync *sync;
933 gint count;
934
935 g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), -1);
936 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1);
937 g_return_val_if_fail (error == NULL || *error == NULL, -1);
938
939 sync = _secret_sync_new ();
940 g_main_context_push_thread_default (sync->context);
941
942 secret_service_unlock (service, objects, cancellable,
943 _secret_sync_on_result, sync);
944
945 g_main_loop_run (sync->loop);
946
947 count = secret_service_unlock_finish (service, sync->result, unlocked, error);
948
949 g_main_context_pop_thread_default (sync->context);
950 _secret_sync_free (sync);
951
952 return count;
953 }
954
955 typedef struct {
956 GCancellable *cancellable;
957 gchar *collection_path;
958 SecretValue *value;
959 GHashTable *properties;
960 gboolean created_collection;
961 gboolean unlocked_collection;
962 } StoreClosure;
963
964 static void
store_closure_free(gpointer data)965 store_closure_free (gpointer data)
966 {
967 StoreClosure *store = data;
968 if (store->cancellable)
969 g_object_unref (store->cancellable);
970 g_free (store->collection_path);
971 secret_value_unref (store->value);
972 g_hash_table_unref (store->properties);
973 g_slice_free (StoreClosure, store);
974 }
975
976 static void
977 on_store_create (GObject *source,
978 GAsyncResult *result,
979 gpointer user_data);
980
981 static void
on_store_keyring(GObject * source,GAsyncResult * result,gpointer user_data)982 on_store_keyring (GObject *source,
983 GAsyncResult *result,
984 gpointer user_data)
985 {
986 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
987 StoreClosure *store = g_simple_async_result_get_op_res_gpointer (async);
988 SecretService *service = SECRET_SERVICE (source);
989 GError *error = NULL;
990 gchar *path;
991
992 path = secret_service_create_collection_dbus_path_finish (service, result, &error);
993 if (error == NULL) {
994 store->created_collection = TRUE;
995 secret_service_create_item_dbus_path (service, store->collection_path,
996 store->properties, store->value,
997 SECRET_ITEM_CREATE_REPLACE, store->cancellable,
998 on_store_create, g_object_ref (async));
999 } else {
1000 g_simple_async_result_take_error (async, error);
1001 g_simple_async_result_complete (async);
1002 }
1003
1004 g_object_unref (async);
1005 g_free (path);
1006 }
1007
1008 static void
on_store_unlock(GObject * source,GAsyncResult * result,gpointer user_data)1009 on_store_unlock (GObject *source,
1010 GAsyncResult *result,
1011 gpointer user_data)
1012 {
1013 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
1014 StoreClosure *store = g_simple_async_result_get_op_res_gpointer (async);
1015 SecretService *service = SECRET_SERVICE (source);
1016 GError *error = NULL;
1017
1018 secret_service_unlock_dbus_paths_finish (service, result, NULL, &error);
1019 if (error == NULL) {
1020 store->unlocked_collection = TRUE;
1021 secret_service_create_item_dbus_path (service, store->collection_path,
1022 store->properties, store->value,
1023 SECRET_ITEM_CREATE_REPLACE, store->cancellable,
1024 on_store_create, g_object_ref (async));
1025 } else {
1026 g_simple_async_result_take_error (async, error);
1027 g_simple_async_result_complete (async);
1028 }
1029
1030 g_object_unref (async);
1031 }
1032
1033 static void
on_store_create(GObject * source,GAsyncResult * result,gpointer user_data)1034 on_store_create (GObject *source,
1035 GAsyncResult *result,
1036 gpointer user_data)
1037 {
1038 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
1039 StoreClosure *store = g_simple_async_result_get_op_res_gpointer (async);
1040 SecretService *service = SECRET_SERVICE (source);
1041 GError *error = NULL;
1042 GHashTable *properties;
1043
1044 _secret_service_create_item_dbus_path_finish_raw (result, &error);
1045
1046 /*
1047 * This happens when the collection doesn't exist. If the collection is
1048 * the default alias, we should try and create it
1049 */
1050
1051 if (!store->created_collection &&
1052 (g_error_matches (error, SECRET_ERROR, SECRET_ERROR_NO_SUCH_OBJECT) ||
1053 g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) &&
1054 g_strcmp0 (store->collection_path, SECRET_ALIAS_PREFIX "default") == 0) {
1055 properties = _secret_collection_properties_new (_("Default keyring"));
1056 secret_service_create_collection_dbus_path (service, properties, "default",
1057 SECRET_COLLECTION_CREATE_NONE, store->cancellable,
1058 on_store_keyring, g_object_ref (async));
1059 g_hash_table_unref (properties);
1060 g_error_free (error);
1061
1062 } else if (!store->unlocked_collection &&
1063 g_error_matches (error, SECRET_ERROR, SECRET_ERROR_IS_LOCKED)) {
1064 const gchar *paths[2] = { store->collection_path, NULL };
1065 secret_service_unlock_dbus_paths (service, paths, store->cancellable,
1066 on_store_unlock, g_object_ref (async));
1067 g_error_free (error);
1068 } else {
1069 if (error != NULL)
1070 g_simple_async_result_take_error (async, error);
1071 g_simple_async_result_complete (async);
1072 }
1073
1074 g_object_unref (async);
1075 }
1076
1077 static void
on_store_service(GObject * source,GAsyncResult * result,gpointer user_data)1078 on_store_service (GObject *source,
1079 GAsyncResult *result,
1080 gpointer user_data)
1081 {
1082 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
1083 StoreClosure *store = g_simple_async_result_get_op_res_gpointer (async);
1084 SecretService *service;
1085 GError *error = NULL;
1086
1087 service = secret_service_get_finish (result, &error);
1088 if (error == NULL) {
1089 secret_service_create_item_dbus_path (service, store->collection_path,
1090 store->properties, store->value,
1091 SECRET_ITEM_CREATE_REPLACE, store->cancellable,
1092 on_store_create, g_object_ref (async));
1093 g_object_unref (service);
1094
1095 } else {
1096 g_simple_async_result_take_error (async, error);
1097 g_simple_async_result_complete (async);
1098 }
1099
1100 g_object_unref (async);
1101 }
1102
1103 /**
1104 * secret_service_store:
1105 * @service: (allow-none): the secret service
1106 * @schema: (allow-none): the schema to use to check attributes
1107 * @attributes: (element-type utf8 utf8): the attribute keys and values
1108 * @collection: (allow-none): a collection alias, or D-Bus object path of the collection where to store the secret
1109 * @label: label for the secret
1110 * @value: the secret value
1111 * @cancellable: optional cancellation object
1112 * @callback: called when the operation completes
1113 * @user_data: data to be passed to the callback
1114 *
1115 * Store a secret value in the secret service.
1116 *
1117 * The @attributes should be a set of key and value string pairs.
1118 *
1119 * If the attributes match a secret item already stored in the collection, then
1120 * the item will be updated with these new values.
1121 *
1122 * If @service is NULL, then secret_service_get() will be called to get
1123 * the default #SecretService proxy.
1124 *
1125 * If @collection is not specified, then the default collection will be
1126 * used. Use #SECRET_COLLECTION_SESSION to store the password in the session
1127 * collection, which doesn't get stored across login sessions.
1128 *
1129 * This method will return immediately and complete asynchronously.
1130 */
1131 void
secret_service_store(SecretService * service,const SecretSchema * schema,GHashTable * attributes,const gchar * collection,const gchar * label,SecretValue * value,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1132 secret_service_store (SecretService *service,
1133 const SecretSchema *schema,
1134 GHashTable *attributes,
1135 const gchar *collection,
1136 const gchar *label,
1137 SecretValue *value,
1138 GCancellable *cancellable,
1139 GAsyncReadyCallback callback,
1140 gpointer user_data)
1141 {
1142 GSimpleAsyncResult *async;
1143 StoreClosure *store;
1144 const gchar *schema_name;
1145 GVariant *propval;
1146
1147 g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service));
1148 g_return_if_fail (attributes != NULL);
1149 g_return_if_fail (label != NULL);
1150 g_return_if_fail (value != NULL);
1151 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1152
1153 /* Warnings raised already */
1154 if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE))
1155 return;
1156
1157 async = g_simple_async_result_new (G_OBJECT (service), callback, user_data,
1158 secret_service_store);
1159 store = g_slice_new0 (StoreClosure);
1160 store->collection_path = _secret_util_collection_to_path (collection);
1161 store->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
1162 store->value = secret_value_ref (value);
1163 store->properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
1164 (GDestroyNotify)g_variant_unref);
1165
1166 propval = g_variant_new_string (label);
1167 g_hash_table_insert (store->properties,
1168 SECRET_ITEM_INTERFACE ".Label",
1169 g_variant_ref_sink (propval));
1170
1171 /* Always store the schema name in the attributes */
1172 schema_name = (schema == NULL) ? NULL : schema->name;
1173 propval = _secret_attributes_to_variant (attributes, schema_name);
1174 g_hash_table_insert (store->properties,
1175 SECRET_ITEM_INTERFACE ".Attributes",
1176 g_variant_ref_sink (propval));
1177
1178 g_simple_async_result_set_op_res_gpointer (async, store, store_closure_free);
1179
1180 if (service == NULL) {
1181 secret_service_get (SECRET_SERVICE_OPEN_SESSION, cancellable,
1182 on_store_service, g_object_ref (async));
1183
1184 } else {
1185 secret_service_create_item_dbus_path (service, store->collection_path,
1186 store->properties, store->value,
1187 SECRET_ITEM_CREATE_REPLACE, store->cancellable,
1188 on_store_create, g_object_ref (async));
1189 }
1190
1191 g_object_unref (async);
1192 }
1193
1194 /**
1195 * secret_service_store_finish:
1196 * @service: (allow-none): the secret service
1197 * @result: the asynchronous result passed to the callback
1198 * @error: location to place an error on failure
1199 *
1200 * Finish asynchronous operation to store a secret value in the secret service.
1201 *
1202 * Returns: whether the storage was successful or not
1203 */
1204 gboolean
secret_service_store_finish(SecretService * service,GAsyncResult * result,GError ** error)1205 secret_service_store_finish (SecretService *service,
1206 GAsyncResult *result,
1207 GError **error)
1208 {
1209 g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE);
1210 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (service),
1211 secret_service_store), FALSE);
1212 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1213
1214 if (_secret_util_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
1215 return FALSE;
1216
1217 return TRUE;
1218 }
1219
1220 /**
1221 * secret_service_store_sync:
1222 * @service: (allow-none): the secret service
1223 * @schema: (allow-none): the schema for the attributes
1224 * @attributes: (element-type utf8 utf8): the attribute keys and values
1225 * @collection: (allow-none): a collection alias, or D-Bus object path of the collection where to store the secret
1226 * @label: label for the secret
1227 * @value: the secret value
1228 * @cancellable: optional cancellation object
1229 * @error: location to place an error on failure
1230 *
1231 * Store a secret value in the secret service.
1232 *
1233 * The @attributes should be a set of key and value string pairs.
1234 *
1235 * If the attributes match a secret item already stored in the collection, then
1236 * the item will be updated with these new values.
1237 *
1238 * If @collection is %NULL, then the default collection will be
1239 * used. Use #SECRET_COLLECTION_SESSION to store the password in the session
1240 * collection, which doesn't get stored across login sessions.
1241 *
1242 * If @service is NULL, then secret_service_get_sync() will be called to get
1243 * the default #SecretService proxy.
1244 *
1245 * This method may block indefinitely and should not be used in user interface
1246 * threads.
1247 *
1248 * Returns: whether the storage was successful or not
1249 */
1250 gboolean
secret_service_store_sync(SecretService * service,const SecretSchema * schema,GHashTable * attributes,const gchar * collection,const gchar * label,SecretValue * value,GCancellable * cancellable,GError ** error)1251 secret_service_store_sync (SecretService *service,
1252 const SecretSchema *schema,
1253 GHashTable *attributes,
1254 const gchar *collection,
1255 const gchar *label,
1256 SecretValue *value,
1257 GCancellable *cancellable,
1258 GError **error)
1259 {
1260 SecretSync *sync;
1261 gboolean ret;
1262
1263 g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE);
1264 g_return_val_if_fail (attributes != NULL, FALSE);
1265 g_return_val_if_fail (label != NULL, FALSE);
1266 g_return_val_if_fail (value != NULL, FALSE);
1267 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1268 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1269
1270 /* Warnings raised already */
1271 if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE))
1272 return FALSE;
1273
1274 sync = _secret_sync_new ();
1275 g_main_context_push_thread_default (sync->context);
1276
1277 secret_service_store (service, schema, attributes, collection,
1278 label, value, cancellable, _secret_sync_on_result, sync);
1279
1280 g_main_loop_run (sync->loop);
1281
1282 ret = secret_service_store_finish (service, sync->result, error);
1283
1284 g_main_context_pop_thread_default (sync->context);
1285 _secret_sync_free (sync);
1286
1287 return ret;
1288 }
1289
1290 typedef struct {
1291 GVariant *attributes;
1292 SecretValue *value;
1293 GCancellable *cancellable;
1294 } LookupClosure;
1295
1296 static void
lookup_closure_free(gpointer data)1297 lookup_closure_free (gpointer data)
1298 {
1299 LookupClosure *closure = data;
1300 g_variant_unref (closure->attributes);
1301 if (closure->value)
1302 secret_value_unref (closure->value);
1303 g_clear_object (&closure->cancellable);
1304 g_slice_free (LookupClosure, closure);
1305 }
1306
1307 static void
on_lookup_get_secret(GObject * source,GAsyncResult * result,gpointer user_data)1308 on_lookup_get_secret (GObject *source,
1309 GAsyncResult *result,
1310 gpointer user_data)
1311 {
1312 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1313 LookupClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
1314 SecretService *self = SECRET_SERVICE (source);
1315 GError *error = NULL;
1316
1317 closure->value = secret_service_get_secret_for_dbus_path_finish (self, result, &error);
1318 if (error != NULL)
1319 g_simple_async_result_take_error (res, error);
1320
1321 g_simple_async_result_complete (res);
1322 g_object_unref (res);
1323 }
1324
1325 static void
on_lookup_unlocked(GObject * source,GAsyncResult * result,gpointer user_data)1326 on_lookup_unlocked (GObject *source,
1327 GAsyncResult *result,
1328 gpointer user_data)
1329 {
1330 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1331 LookupClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
1332 SecretService *self = SECRET_SERVICE (source);
1333 GError *error = NULL;
1334 gchar **unlocked = NULL;
1335
1336 secret_service_unlock_dbus_paths_finish (SECRET_SERVICE (source),
1337 result, &unlocked, &error);
1338 if (error != NULL) {
1339 g_simple_async_result_take_error (res, error);
1340 g_simple_async_result_complete (res);
1341
1342 } else if (unlocked && unlocked[0]) {
1343 secret_service_get_secret_for_dbus_path (self, unlocked[0],
1344 closure->cancellable,
1345 on_lookup_get_secret,
1346 g_object_ref (res));
1347
1348 } else {
1349 g_simple_async_result_complete (res);
1350 }
1351
1352 g_strfreev (unlocked);
1353 g_object_unref (res);
1354 }
1355
1356 static void
on_lookup_searched(GObject * source,GAsyncResult * result,gpointer user_data)1357 on_lookup_searched (GObject *source,
1358 GAsyncResult *result,
1359 gpointer user_data)
1360 {
1361 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1362 LookupClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
1363 SecretService *self = SECRET_SERVICE (source);
1364 GError *error = NULL;
1365 gchar **unlocked = NULL;
1366 gchar **locked = NULL;
1367
1368 secret_service_search_for_dbus_paths_finish (self, result, &unlocked, &locked, &error);
1369 if (error != NULL) {
1370 g_simple_async_result_take_error (res, error);
1371 g_simple_async_result_complete (res);
1372
1373 } else if (unlocked && unlocked[0]) {
1374 secret_service_get_secret_for_dbus_path (self, unlocked[0],
1375 closure->cancellable,
1376 on_lookup_get_secret,
1377 g_object_ref (res));
1378
1379 } else if (locked && locked[0]) {
1380 const gchar *paths[] = { locked[0], NULL };
1381 secret_service_unlock_dbus_paths (self, paths,
1382 closure->cancellable,
1383 on_lookup_unlocked,
1384 g_object_ref (res));
1385
1386 } else {
1387 g_simple_async_result_complete (res);
1388 }
1389
1390 g_strfreev (unlocked);
1391 g_strfreev (locked);
1392 g_object_unref (res);
1393 }
1394
1395 static void
on_lookup_service(GObject * source,GAsyncResult * result,gpointer user_data)1396 on_lookup_service (GObject *source,
1397 GAsyncResult *result,
1398 gpointer user_data)
1399 {
1400 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
1401 LookupClosure *lookup = g_simple_async_result_get_op_res_gpointer (async);
1402 SecretService *service;
1403 GError *error = NULL;
1404
1405 service = secret_service_get_finish (result, &error);
1406 if (error == NULL) {
1407 _secret_service_search_for_paths_variant (service, lookup->attributes,
1408 lookup->cancellable,
1409 on_lookup_searched, g_object_ref (async));
1410 g_object_unref (service);
1411
1412 } else {
1413 g_simple_async_result_take_error (async, error);
1414 g_simple_async_result_complete (async);
1415 }
1416
1417 g_object_unref (async);
1418 }
1419
1420 /**
1421 * secret_service_lookup:
1422 * @service: (allow-none): the secret service
1423 * @schema: (allow-none): the schema for the attributes
1424 * @attributes: (element-type utf8 utf8): the attribute keys and values
1425 * @cancellable: optional cancellation object
1426 * @callback: called when the operation completes
1427 * @user_data: data to be passed to the callback
1428 *
1429 * Lookup a secret value in the secret service.
1430 *
1431 * The @attributes should be a set of key and value string pairs.
1432 *
1433 * If @service is NULL, then secret_service_get() will be called to get
1434 * the default #SecretService proxy.
1435 *
1436 * This method will return immediately and complete asynchronously.
1437 */
1438 void
secret_service_lookup(SecretService * service,const SecretSchema * schema,GHashTable * attributes,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1439 secret_service_lookup (SecretService *service,
1440 const SecretSchema *schema,
1441 GHashTable *attributes,
1442 GCancellable *cancellable,
1443 GAsyncReadyCallback callback,
1444 gpointer user_data)
1445 {
1446 const gchar *schema_name = NULL;
1447 GSimpleAsyncResult *res;
1448 LookupClosure *closure;
1449
1450 g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service));
1451 g_return_if_fail (attributes != NULL);
1452 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1453
1454 /* Warnings raised already */
1455 if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
1456 return;
1457
1458 if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME))
1459 schema_name = schema->name;
1460
1461 res = g_simple_async_result_new (G_OBJECT (service), callback, user_data,
1462 secret_service_lookup);
1463 closure = g_slice_new0 (LookupClosure);
1464 closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
1465 closure->attributes = _secret_attributes_to_variant (attributes, schema_name);
1466 g_variant_ref_sink (closure->attributes);
1467 g_simple_async_result_set_op_res_gpointer (res, closure, lookup_closure_free);
1468
1469 if (service == NULL) {
1470 secret_service_get (SECRET_SERVICE_OPEN_SESSION, cancellable,
1471 on_lookup_service, g_object_ref (res));
1472 } else {
1473 _secret_service_search_for_paths_variant (service, closure->attributes,
1474 closure->cancellable,
1475 on_lookup_searched, g_object_ref (res));
1476 }
1477
1478 g_object_unref (res);
1479 }
1480
1481 /**
1482 * secret_service_lookup_finish:
1483 * @service: (allow-none): the secret service
1484 * @result: the asynchronous result passed to the callback
1485 * @error: location to place an error on failure
1486 *
1487 * Finish asynchronous operation to lookup a secret value in the secret service.
1488 *
1489 * If no secret is found then %NULL is returned.
1490 *
1491 * Returns: (transfer full): a newly allocated #SecretValue, which should be
1492 * released with secret_value_unref(), or %NULL if no secret found
1493 */
1494 SecretValue *
secret_service_lookup_finish(SecretService * service,GAsyncResult * result,GError ** error)1495 secret_service_lookup_finish (SecretService *service,
1496 GAsyncResult *result,
1497 GError **error)
1498 {
1499 GSimpleAsyncResult *res;
1500 LookupClosure *closure;
1501 SecretValue *value;
1502
1503 g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL);
1504 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1505 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (service),
1506 secret_service_lookup), NULL);
1507
1508 res = G_SIMPLE_ASYNC_RESULT (result);
1509 if (_secret_util_propagate_error (res, error))
1510 return NULL;
1511
1512 closure = g_simple_async_result_get_op_res_gpointer (res);
1513 value = closure->value;
1514 closure->value = NULL;
1515 return value;
1516 }
1517
1518 /**
1519 * secret_service_lookup_sync:
1520 * @service: (allow-none): the secret service
1521 * @schema: (allow-none): the schema for the attributes
1522 * @attributes: (element-type utf8 utf8): the attribute keys and values
1523 * @cancellable: optional cancellation object
1524 * @error: location to place an error on failure
1525 *
1526 * Lookup a secret value in the secret service.
1527 *
1528 * The @attributes should be a set of key and value string pairs.
1529 *
1530 * If @service is NULL, then secret_service_get_sync() will be called to get
1531 * the default #SecretService proxy.
1532 *
1533 * This method may block indefinitely and should not be used in user interface
1534 * threads.
1535 *
1536 * Returns: (transfer full): a newly allocated #SecretValue, which should be
1537 * released with secret_value_unref(), or %NULL if no secret found
1538 */
1539 SecretValue *
secret_service_lookup_sync(SecretService * service,const SecretSchema * schema,GHashTable * attributes,GCancellable * cancellable,GError ** error)1540 secret_service_lookup_sync (SecretService *service,
1541 const SecretSchema *schema,
1542 GHashTable *attributes,
1543 GCancellable *cancellable,
1544 GError **error)
1545 {
1546 SecretSync *sync;
1547 SecretValue *value;
1548
1549 g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL);
1550 g_return_val_if_fail (attributes != NULL, NULL);
1551 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
1552
1553 /* Warnings raised already */
1554 if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
1555 return NULL;
1556
1557 sync = _secret_sync_new ();
1558 g_main_context_push_thread_default (sync->context);
1559
1560 secret_service_lookup (service, schema, attributes, cancellable,
1561 _secret_sync_on_result, sync);
1562
1563 g_main_loop_run (sync->loop);
1564
1565 value = secret_service_lookup_finish (service, sync->result, error);
1566
1567 g_main_context_pop_thread_default (sync->context);
1568 _secret_sync_free (sync);
1569
1570 return value;
1571 }
1572
1573 typedef struct {
1574 GCancellable *cancellable;
1575 SecretService *service;
1576 GVariant *attributes;
1577 gint deleted;
1578 gint deleting;
1579 } DeleteClosure;
1580
1581 static void
delete_closure_free(gpointer data)1582 delete_closure_free (gpointer data)
1583 {
1584 DeleteClosure *closure = data;
1585 if (closure->service)
1586 g_object_unref (closure->service);
1587 g_variant_unref (closure->attributes);
1588 g_clear_object (&closure->cancellable);
1589 g_slice_free (DeleteClosure, closure);
1590 }
1591
1592 static void
on_delete_password_complete(GObject * source,GAsyncResult * result,gpointer user_data)1593 on_delete_password_complete (GObject *source,
1594 GAsyncResult *result,
1595 gpointer user_data)
1596 {
1597 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1598 DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
1599 GError *error = NULL;
1600 gboolean deleted;
1601
1602 closure->deleting--;
1603
1604 deleted = _secret_service_delete_path_finish (SECRET_SERVICE (source), result, &error);
1605 if (error != NULL)
1606 g_simple_async_result_take_error (res, error);
1607 if (deleted)
1608 closure->deleted++;
1609
1610 if (closure->deleting <= 0)
1611 g_simple_async_result_complete (res);
1612
1613 g_object_unref (res);
1614 }
1615
1616 static void
on_delete_searched(GObject * source,GAsyncResult * result,gpointer user_data)1617 on_delete_searched (GObject *source,
1618 GAsyncResult *result,
1619 gpointer user_data)
1620 {
1621 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1622 DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
1623 GError *error = NULL;
1624 gchar **unlocked = NULL;
1625 gint i;
1626
1627 secret_service_search_for_dbus_paths_finish (SECRET_SERVICE (source), result, &unlocked, NULL, &error);
1628 if (error == NULL) {
1629 for (i = 0; unlocked[i] != NULL; i++) {
1630 _secret_service_delete_path (closure->service, unlocked[i], TRUE,
1631 closure->cancellable,
1632 on_delete_password_complete,
1633 g_object_ref (res));
1634 closure->deleting++;
1635 }
1636
1637 if (closure->deleting == 0)
1638 g_simple_async_result_complete (res);
1639 } else {
1640 g_simple_async_result_take_error (res, error);
1641 g_simple_async_result_complete (res);
1642 }
1643
1644 g_strfreev (unlocked);
1645 g_object_unref (res);
1646 }
1647
1648 static void
on_delete_service(GObject * source,GAsyncResult * result,gpointer user_data)1649 on_delete_service (GObject *source,
1650 GAsyncResult *result,
1651 gpointer user_data)
1652 {
1653 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
1654 DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (async);
1655 GError *error = NULL;
1656
1657 closure->service = secret_service_get_finish (result, &error);
1658 if (error == NULL) {
1659 _secret_service_search_for_paths_variant (closure->service, closure->attributes,
1660 closure->cancellable,
1661 on_delete_searched, g_object_ref (async));
1662
1663 } else {
1664 g_simple_async_result_take_error (async, error);
1665 g_simple_async_result_complete (async);
1666 }
1667
1668 g_object_unref (async);
1669 }
1670
1671 /**
1672 * secret_service_clear:
1673 * @service: (allow-none): the secret service
1674 * @schema: (allow-none): the schema for the attributes
1675 * @attributes: (element-type utf8 utf8): the attribute keys and values
1676 * @cancellable: optional cancellation object
1677 * @callback: called when the operation completes
1678 * @user_data: data to be passed to the callback
1679 *
1680 * Remove unlocked items which match the attributes from the secret service.
1681 *
1682 * The @attributes should be a set of key and value string pairs.
1683 *
1684 * If @service is NULL, then secret_service_get() will be called to get
1685 * the default #SecretService proxy.
1686 *
1687 * This method will return immediately and complete asynchronously.
1688 */
1689 void
secret_service_clear(SecretService * service,const SecretSchema * schema,GHashTable * attributes,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1690 secret_service_clear (SecretService *service,
1691 const SecretSchema *schema,
1692 GHashTable *attributes,
1693 GCancellable *cancellable,
1694 GAsyncReadyCallback callback,
1695 gpointer user_data)
1696 {
1697 const gchar *schema_name = NULL;
1698 GSimpleAsyncResult *res;
1699 DeleteClosure *closure;
1700
1701 g_return_if_fail (service == NULL || SECRET_SERVICE (service));
1702 g_return_if_fail (attributes != NULL);
1703 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1704
1705 /* Warnings raised already */
1706 if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
1707 return;
1708
1709 if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME))
1710 schema_name = schema->name;
1711
1712 res = g_simple_async_result_new (G_OBJECT (service), callback, user_data,
1713 secret_service_clear);
1714 closure = g_slice_new0 (DeleteClosure);
1715 closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
1716 closure->attributes = _secret_attributes_to_variant (attributes, schema_name);
1717 g_variant_ref_sink (closure->attributes);
1718 g_simple_async_result_set_op_res_gpointer (res, closure, delete_closure_free);
1719
1720 /* A double check to make sure we don't delete everything, should have been checked earlier */
1721 g_assert (g_variant_n_children (closure->attributes) > 0);
1722
1723 if (service == NULL) {
1724 secret_service_get (SECRET_SERVICE_NONE, cancellable,
1725 on_delete_service, g_object_ref (res));
1726 } else {
1727 closure->service = g_object_ref (service);
1728 _secret_service_search_for_paths_variant (closure->service, closure->attributes,
1729 closure->cancellable,
1730 on_delete_searched, g_object_ref (res));
1731 }
1732
1733 g_object_unref (res);
1734 }
1735
1736 /**
1737 * secret_service_clear_finish:
1738 * @service: (allow-none): the secret service
1739 * @result: the asynchronous result passed to the callback
1740 * @error: location to place an error on failure
1741 *
1742 * Finish asynchronous operation to remove items from the secret
1743 * service.
1744 *
1745 * Returns: whether items were removed or not
1746 */
1747 gboolean
secret_service_clear_finish(SecretService * service,GAsyncResult * result,GError ** error)1748 secret_service_clear_finish (SecretService *service,
1749 GAsyncResult *result,
1750 GError **error)
1751 {
1752 GSimpleAsyncResult *res;
1753 DeleteClosure *closure;
1754
1755 g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE);
1756 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1757 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (service),
1758 secret_service_clear), FALSE);
1759
1760 res = G_SIMPLE_ASYNC_RESULT (result);
1761 if (_secret_util_propagate_error (res, error))
1762 return FALSE;
1763
1764 closure = g_simple_async_result_get_op_res_gpointer (res);
1765 return closure->deleted > 0;
1766 }
1767
1768 /**
1769 * secret_service_clear_sync:
1770 * @service: (allow-none): the secret service
1771 * @schema: (allow-none): the schema for the attributes
1772 * @attributes: (element-type utf8 utf8): the attribute keys and values
1773 * @cancellable: optional cancellation object
1774 * @error: location to place an error on failure
1775 *
1776 * Remove unlocked items which match the attributes from the secret service.
1777 *
1778 * The @attributes should be a set of key and value string pairs.
1779 *
1780 * If @service is NULL, then secret_service_get_sync() will be called to get
1781 * the default #SecretService proxy.
1782 *
1783 * This method may block indefinitely and should not be used in user interface
1784 * threads.
1785 *
1786 * Returns: whether items were removed or not
1787 */
1788 gboolean
secret_service_clear_sync(SecretService * service,const SecretSchema * schema,GHashTable * attributes,GCancellable * cancellable,GError ** error)1789 secret_service_clear_sync (SecretService *service,
1790 const SecretSchema *schema,
1791 GHashTable *attributes,
1792 GCancellable *cancellable,
1793 GError **error)
1794 {
1795 SecretSync *sync;
1796 gboolean result;
1797
1798 g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE);
1799 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1800 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1801
1802 /* Warnings raised already */
1803 if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
1804 return FALSE;
1805
1806 sync = _secret_sync_new ();
1807 g_main_context_push_thread_default (sync->context);
1808
1809 secret_service_clear (service, schema, attributes, cancellable,
1810 _secret_sync_on_result, sync);
1811
1812 g_main_loop_run (sync->loop);
1813
1814 result = secret_service_clear_finish (service, sync->result, error);
1815
1816 g_main_context_pop_thread_default (sync->context);
1817 _secret_sync_free (sync);
1818
1819 return result;
1820 }
1821
1822 typedef struct {
1823 GCancellable *cancellable;
1824 gchar *alias;
1825 gchar *collection_path;
1826 } SetClosure;
1827
1828 static void
set_closure_free(gpointer data)1829 set_closure_free (gpointer data)
1830 {
1831 SetClosure *set = data;
1832 if (set->cancellable)
1833 g_object_unref (set->cancellable);
1834 g_free (set->alias);
1835 g_free (set->collection_path);
1836 g_slice_free (SetClosure, set);
1837 }
1838
1839 static void
on_set_alias_done(GObject * source,GAsyncResult * result,gpointer user_data)1840 on_set_alias_done (GObject *source,
1841 GAsyncResult *result,
1842 gpointer user_data)
1843 {
1844 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
1845 GError *error = NULL;
1846
1847 secret_service_set_alias_to_dbus_path_finish (SECRET_SERVICE (source), result, &error);
1848 if (error != NULL)
1849 g_simple_async_result_take_error (async, error);
1850
1851 g_simple_async_result_complete (async);
1852 g_object_unref (async);
1853 }
1854
1855 static void
on_set_alias_service(GObject * source,GAsyncResult * result,gpointer user_data)1856 on_set_alias_service (GObject *source,
1857 GAsyncResult *result,
1858 gpointer user_data)
1859 {
1860 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
1861 SetClosure *set = g_simple_async_result_get_op_res_gpointer (async);
1862 SecretService *service;
1863 GError *error = NULL;
1864
1865 service = secret_service_get_finish (result, &error);
1866 if (error == NULL) {
1867 secret_service_set_alias_to_dbus_path (service, set->alias,
1868 set->collection_path,
1869 set->cancellable,
1870 on_set_alias_done,
1871 g_object_ref (async));
1872 g_object_unref (service);
1873
1874 } else {
1875 g_simple_async_result_take_error (async, error);
1876 g_simple_async_result_complete (async);
1877 }
1878
1879 g_object_unref (async);
1880 }
1881
1882 /**
1883 * secret_service_set_alias:
1884 * @service: (allow-none): a secret service object
1885 * @alias: the alias to assign the collection to
1886 * @collection: (allow-none): the collection to assign to the alias
1887 * @cancellable: (allow-none): optional cancellation object
1888 * @callback: called when the operation completes
1889 * @user_data: data to pass to the callback
1890 *
1891 * Assign a collection to this alias. Aliases help determine
1892 * well known collections, such as 'default'.
1893 *
1894 * If @service is NULL, then secret_service_get() will be called to get
1895 * the default #SecretService proxy.
1896 *
1897 * This method will return immediately and complete asynchronously.
1898 */
1899 void
secret_service_set_alias(SecretService * service,const gchar * alias,SecretCollection * collection,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1900 secret_service_set_alias (SecretService *service,
1901 const gchar *alias,
1902 SecretCollection *collection,
1903 GCancellable *cancellable,
1904 GAsyncReadyCallback callback,
1905 gpointer user_data)
1906 {
1907 GSimpleAsyncResult *async;
1908 SetClosure *set;
1909 const gchar *path;
1910
1911 g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service));
1912 g_return_if_fail (alias != NULL);
1913 g_return_if_fail (collection == NULL || SECRET_IS_COLLECTION (collection));
1914 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1915
1916 async = g_simple_async_result_new (G_OBJECT (service), callback, user_data,
1917 secret_service_set_alias);
1918 set = g_slice_new0 (SetClosure);
1919 set->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
1920 set->alias = g_strdup (alias);
1921
1922 if (collection) {
1923 path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection));
1924 g_return_if_fail (path != NULL);
1925 } else {
1926 path = NULL;
1927 }
1928
1929 set->collection_path = g_strdup (path);
1930 g_simple_async_result_set_op_res_gpointer (async, set, set_closure_free);
1931
1932 if (service == NULL) {
1933 secret_service_get (SECRET_SERVICE_NONE, cancellable,
1934 on_set_alias_service, g_object_ref (async));
1935 } else {
1936 secret_service_set_alias_to_dbus_path (service, set->alias,
1937 set->collection_path,
1938 set->cancellable,
1939 on_set_alias_done,
1940 g_object_ref (async));
1941 }
1942
1943 g_object_unref (async);
1944 }
1945
1946 /**
1947 * secret_service_set_alias_finish:
1948 * @service: (allow-none): a secret service object
1949 * @result: asynchronous result passed to callback
1950 * @error: location to place error on failure
1951 *
1952 * Finish an asynchronous operation to assign a collection to an alias.
1953 *
1954 * Returns: %TRUE if successful
1955 */
1956 gboolean
secret_service_set_alias_finish(SecretService * service,GAsyncResult * result,GError ** error)1957 secret_service_set_alias_finish (SecretService *service,
1958 GAsyncResult *result,
1959 GError **error)
1960 {
1961 g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE);
1962 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (service),
1963 secret_service_set_alias), FALSE);
1964 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1965
1966 if (_secret_util_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
1967 return FALSE;
1968
1969 return TRUE;
1970 }
1971
1972 /**
1973 * secret_service_set_alias_sync:
1974 * @service: (allow-none): a secret service object
1975 * @alias: the alias to assign the collection to
1976 * @collection: (allow-none): the collection to assign to the alias
1977 * @cancellable: (allow-none): optional cancellation object
1978 * @error: location to place error on failure
1979 *
1980 * Assign a collection to this alias. Aliases help determine
1981 * well known collections, such as 'default'.
1982 *
1983 * If @service is NULL, then secret_service_get_sync() will be called to get
1984 * the default #SecretService proxy.
1985 *
1986 * This method may block and should not be used in user interface threads.
1987 *
1988 * Returns: %TRUE if successful
1989 */
1990 gboolean
secret_service_set_alias_sync(SecretService * service,const gchar * alias,SecretCollection * collection,GCancellable * cancellable,GError ** error)1991 secret_service_set_alias_sync (SecretService *service,
1992 const gchar *alias,
1993 SecretCollection *collection,
1994 GCancellable *cancellable,
1995 GError **error)
1996 {
1997 SecretSync *sync;
1998 gboolean ret;
1999
2000 g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE);
2001 g_return_val_if_fail (alias != NULL, FALSE);
2002 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
2003 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2004
2005 sync = _secret_sync_new ();
2006 g_main_context_push_thread_default (sync->context);
2007
2008 secret_service_set_alias (service, alias, collection, cancellable,
2009 _secret_sync_on_result, sync);
2010
2011 g_main_loop_run (sync->loop);
2012
2013 ret = secret_service_set_alias_finish (service, sync->result, error);
2014
2015 g_main_context_pop_thread_default (sync->context);
2016 _secret_sync_free (sync);
2017
2018 return ret;
2019 }
2020