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