1 /* libsecret - GLib wrapper for Secret Service
2  *
3  * Copyright 2011 Collabora Ltd.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published
7  * by the Free Software Foundation; either version 2.1 of the licence or (at
8  * your option) any later version.
9  *
10  * See the included COPYING file for more information.
11  *
12  * Author: Stef Walter <stefw@gnome.org>
13  */
14 
15 #include "config.h"
16 
17 #include "secret-attributes.h"
18 #include "secret-password.h"
19 #include "secret-private.h"
20 #include "secret-retrievable.h"
21 #include "secret-backend.h"
22 #include "secret-value.h"
23 
24 #include <egg/egg-secure-memory.h>
25 
26 /**
27  * SECTION:secret-password
28  * @title: Password storage
29  * @short_description: Simple password storage and lookup
30  *
31  * This is a simple API for storing passwords and retrieving passwords in the
32  * Secret Service.
33  *
34  * Each password is associated with a set of attributes. Attribute values can
35  * be either strings, integers or booleans.
36  *
37  * The names and types of allowed attributes for a given password are defined
38  * with a schema. Certain schemas are predefined. Additional schemas can be
39  * defined via the %SecretSchema structure.
40  *
41  * Each of the functions accept a variable list of attributes names and their
42  * values. Include a %NULL to terminate the list of attributes.
43  *
44  * Stability: Stable
45  */
46 
47 /**
48  * secret_password_store: (skip)
49  * @schema: the schema for attributes
50  * @collection: (allow-none): a collection alias, or D-Bus object path of the collection where to store the secret
51  * @label: label for the secret
52  * @password: the null-terminated password to store
53  * @cancellable: optional cancellation object
54  * @callback: called when the operation completes
55  * @user_data: data to be passed to the callback
56  * @...: the attribute keys and values, terminated with %NULL
57  *
58  * Store a password in the secret service.
59  *
60  * The variable argument list should contain pairs of a) The attribute name as
61  * a null-terminated string, followed by b) attribute value, either a character
62  * string, an int number, or a gboolean value, as defined in the @schema.
63  * The list of attribtues should be terminated with a %NULL.
64  *
65  * If the attributes match a secret item already stored in the collection, then
66  * the item will be updated with these new values.
67  *
68  * If @collection is %NULL, then the default collection will be
69  * used. Use #SECRET_COLLECTION_SESSION to store the password in the session
70  * collection, which doesn't get stored across login sessions.
71  *
72  * This method will return immediately and complete asynchronously.
73  */
74 void
secret_password_store(const SecretSchema * schema,const gchar * collection,const gchar * label,const gchar * password,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data,...)75 secret_password_store (const SecretSchema *schema,
76                        const gchar *collection,
77                        const gchar *label,
78                        const gchar *password,
79                        GCancellable *cancellable,
80                        GAsyncReadyCallback callback,
81                        gpointer user_data,
82                        ...)
83 {
84 	GHashTable *attributes;
85 	va_list va;
86 
87 	g_return_if_fail (schema != NULL);
88 	g_return_if_fail (label != NULL);
89 	g_return_if_fail (password != NULL);
90 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
91 
92 	va_start (va, user_data);
93 	attributes = secret_attributes_buildv (schema, va);
94 	va_end (va);
95 
96 	/* Precondition failed, already warned */
97 	if (!attributes)
98 		return;
99 
100 	secret_password_storev (schema, attributes, collection, label, password,
101 	                        cancellable, callback, user_data);
102 
103 	g_hash_table_unref (attributes);
104 }
105 
106 typedef struct {
107 	const SecretSchema *schema;
108 	GHashTable *attributes;
109 	gchar *collection;
110 	gchar *label;
111 	SecretValue *value;
112 } StoreClosure;
113 
114 static void
store_closure_free(gpointer data)115 store_closure_free (gpointer data)
116 {
117 	StoreClosure *store = data;
118 	_secret_schema_unref_if_nonstatic (store->schema);
119 	g_hash_table_unref (store->attributes);
120 	g_free (store->collection);
121 	g_free (store->label);
122 	secret_value_unref (store->value);
123 	g_slice_free (StoreClosure, store);
124 }
125 
126 static void
on_store(GObject * source,GAsyncResult * result,gpointer user_data)127 on_store (GObject *source,
128 	  GAsyncResult *result,
129 	  gpointer user_data)
130 {
131 	GTask *task = G_TASK (user_data);
132 	SecretBackend *backend = SECRET_BACKEND (source);
133 	SecretBackendInterface *iface;
134 	GError *error = NULL;
135 
136 	iface = SECRET_BACKEND_GET_IFACE (backend);
137 	g_return_if_fail (iface->store_finish != NULL);
138 
139 	if (!iface->store_finish (backend, result, &error)) {
140 		g_task_return_error (task, error);
141 		g_object_unref (task);
142 		return;
143 	}
144 
145 	g_task_return_boolean (task, TRUE);
146 	g_object_unref (task);
147 }
148 
149 static void
on_store_backend(GObject * source,GAsyncResult * result,gpointer user_data)150 on_store_backend (GObject *source,
151                   GAsyncResult *result,
152                   gpointer user_data)
153 {
154 	GTask *task = G_TASK (user_data);
155 	StoreClosure *store = g_task_get_task_data (task);
156 	SecretBackend *backend;
157 	SecretBackendInterface *iface;
158 	GError *error = NULL;
159 
160 	backend = secret_backend_get_finish (result, &error);
161 	if (backend == NULL) {
162 		g_task_return_error (task, error);
163 		g_object_unref (task);
164 		return;
165 	}
166 
167 	iface = SECRET_BACKEND_GET_IFACE (backend);
168 	g_return_if_fail (iface->store != NULL);
169 
170 	iface->store (backend, store->schema, store->attributes,
171 		      store->collection, store->label, store->value,
172 		      g_task_get_cancellable (task),
173 		      on_store,
174 		      task);
175 }
176 
177 /**
178  * secret_password_storev: (rename-to secret_password_store)
179  * @schema: (nullable): the schema for attributes
180  * @attributes: (element-type utf8 utf8) (transfer full): the attribute keys and values
181  * @collection: (allow-none): a collection alias, or D-Bus object path of the collection where to store the secret
182  * @label: label for the secret
183  * @password: the null-terminated password to store
184  * @cancellable: optional cancellation object
185  * @callback: (scope async): called when the operation completes
186  * @user_data: data to be passed to the callback
187  *
188  * Store a password in the secret service.
189  *
190  * The @attributes should be a set of key and value string pairs.
191  *
192  * If the attributes match a secret item already stored in the collection, then
193  * the item will be updated with these new values.
194  *
195  * If @collection is %NULL, then the default collection will be
196  * used. Use #SECRET_COLLECTION_SESSION to store the password in the session
197  * collection, which doesn't get stored across login sessions.
198  *
199  * This method will return immediately and complete asynchronously.
200  */
201 void
secret_password_storev(const SecretSchema * schema,GHashTable * attributes,const gchar * collection,const gchar * label,const gchar * password,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)202 secret_password_storev (const SecretSchema *schema,
203                         GHashTable *attributes,
204                         const gchar *collection,
205                         const gchar *label,
206                         const gchar *password,
207                         GCancellable *cancellable,
208                         GAsyncReadyCallback callback,
209                         gpointer user_data)
210 {
211 	StoreClosure *store;
212 	GTask *task;
213 
214 	g_return_if_fail (label != NULL);
215 	g_return_if_fail (password != NULL);
216 	g_return_if_fail (attributes != NULL);
217 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
218 
219 	/* Warnings raised already */
220 	if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE))
221 		return;
222 
223 	task = g_task_new (NULL, cancellable, callback, user_data);
224 	store = g_slice_new0 (StoreClosure);
225 	store->schema = _secret_schema_ref_if_nonstatic (schema);
226 	store->attributes = g_hash_table_ref (attributes);
227 	store->collection = g_strdup (collection);
228 	store->label = g_strdup (label);
229 	store->value = secret_value_new (password, -1, "text/plain");
230 	g_task_set_task_data (task, store, store_closure_free);
231 
232 	secret_backend_get (SECRET_BACKEND_OPEN_SESSION,
233 			    cancellable,
234 			    on_store_backend, task);
235 }
236 
237 /**
238  * secret_password_store_binary: (skip)
239  * @schema: the schema for attributes
240  * @collection: (allow-none): a collection alias, or D-Bus object path of the collection where to store the secret
241  * @label: label for the secret
242  * @value: a #SecretValue
243  * @cancellable: optional cancellation object
244  * @callback: called when the operation completes
245  * @user_data: data to be passed to the callback
246  * @...: the attribute keys and values, terminated with %NULL
247  *
248  * Store a password in the secret service.
249  *
250  * This is similar to secret_password_store(), but takes a
251  * #SecretValue as the argument instead of a null-terminated password.
252  *
253  * This method will return immediately and complete asynchronously.
254  *
255  * Since: 0.19.0
256  */
257 void
secret_password_store_binary(const SecretSchema * schema,const gchar * collection,const gchar * label,SecretValue * value,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data,...)258 secret_password_store_binary (const SecretSchema *schema,
259 			      const gchar *collection,
260 			      const gchar *label,
261 			      SecretValue *value,
262 			      GCancellable *cancellable,
263 			      GAsyncReadyCallback callback,
264 			      gpointer user_data,
265 			      ...)
266 {
267 	GHashTable *attributes;
268 	va_list va;
269 
270 	g_return_if_fail (schema != NULL);
271 	g_return_if_fail (label != NULL);
272 	g_return_if_fail (value != NULL);
273 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
274 
275 	va_start (va, user_data);
276 	attributes = secret_attributes_buildv (schema, va);
277 	va_end (va);
278 
279 	/* Precondition failed, already warned */
280 	if (!attributes)
281 		return;
282 
283 	secret_password_storev_binary (schema, attributes, collection, label, value,
284 				       cancellable, callback, user_data);
285 
286 	g_hash_table_unref (attributes);
287 }
288 
289 /**
290  * secret_password_storev_binary: (rename-to secret_password_store_binary)
291  * @schema: (nullable): the schema for attributes
292  * @attributes: (element-type utf8 utf8) (transfer full): the attribute keys and values
293  * @collection: (allow-none): a collection alias, or D-Bus object path of the collection where to store the secret
294  * @label: label for the secret
295  * @value: a #SecretValue
296  * @cancellable: optional cancellation object
297  * @callback: (scope async): called when the operation completes
298  * @user_data: data to be passed to the callback
299  *
300  * Store a password in the secret service.
301  *
302  * This is similar to secret_password_storev(), but takes a
303  * #SecretValue as the argument instead of a null-terminated password.
304  *
305  * This method will return immediately and complete asynchronously.
306  *
307  * Since: 0.19.0
308  */
309 void
secret_password_storev_binary(const SecretSchema * schema,GHashTable * attributes,const gchar * collection,const gchar * label,SecretValue * value,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)310 secret_password_storev_binary (const SecretSchema *schema,
311 			       GHashTable *attributes,
312 			       const gchar *collection,
313 			       const gchar *label,
314 			       SecretValue *value,
315 			       GCancellable *cancellable,
316 			       GAsyncReadyCallback callback,
317 			       gpointer user_data)
318 {
319 	StoreClosure *store;
320 	GTask *task;
321 
322 	g_return_if_fail (label != NULL);
323 	g_return_if_fail (value != NULL);
324 	g_return_if_fail (attributes != NULL);
325 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
326 
327 	/* Warnings raised already */
328 	if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE))
329 		return;
330 
331 	task = g_task_new (NULL, cancellable, callback, user_data);
332 	store = g_slice_new0 (StoreClosure);
333 	store->schema = _secret_schema_ref_if_nonstatic (schema);
334 	store->attributes = g_hash_table_ref (attributes);
335 	store->collection = g_strdup (collection);
336 	store->label = g_strdup (label);
337 	store->value = secret_value_ref (value);
338 	g_task_set_task_data (task, store, store_closure_free);
339 
340 	secret_backend_get (SECRET_BACKEND_OPEN_SESSION,
341 			    cancellable,
342 			    on_store_backend, task);
343 }
344 
345 /**
346  * secret_password_store_finish:
347  * @result: the asynchronous result passed to the callback
348  * @error: location to place an error on failure
349  *
350  * Finish asynchronous operation to store a password in the secret service.
351  *
352  * Returns: whether the storage was successful or not
353  */
354 gboolean
secret_password_store_finish(GAsyncResult * result,GError ** error)355 secret_password_store_finish (GAsyncResult *result,
356                               GError **error)
357 {
358 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
359 	g_return_val_if_fail (g_task_is_valid (result, NULL), FALSE);
360 
361 	return g_task_propagate_boolean (G_TASK (result), error);
362 }
363 
364 /**
365  * secret_password_store_sync:
366  * @schema: the schema for attributes
367  * @collection: (allow-none): a collection alias, or D-Bus object path of the collection where to store the secret
368  * @label: label for the secret
369  * @password: the null-terminated password to store
370  * @cancellable: optional cancellation object
371  * @error: location to place an error on failure
372  * @...: the attribute keys and values, terminated with %NULL
373  *
374  * Store a password in the secret service.
375  *
376  * The variable argument list should contain pairs of a) The attribute name as
377  * a null-terminated string, followed by b) attribute value, either a character
378  * string, an int number, or a gboolean value, as defined in the @schema.
379  * The list of attribtues should be terminated with a %NULL.
380  *
381  * If the attributes match a secret item already stored in the collection, then
382  * the item will be updated with these new values.
383  *
384  * If @collection is %NULL, then the default collection will be
385  * used. Use #SECRET_COLLECTION_SESSION to store the password in the session
386  * collection, which doesn't get stored across login sessions.
387  *
388  * This method may block indefinitely and should not be used in user interface
389  * threads.
390  *
391  * Returns: whether the storage was successful or not
392  */
393 gboolean
secret_password_store_sync(const SecretSchema * schema,const gchar * collection,const gchar * label,const gchar * password,GCancellable * cancellable,GError ** error,...)394 secret_password_store_sync (const SecretSchema *schema,
395                             const gchar *collection,
396                             const gchar *label,
397                             const gchar *password,
398                             GCancellable *cancellable,
399                             GError **error,
400                             ...)
401 {
402 	GHashTable *attributes;
403 	va_list va;
404 	gboolean ret;
405 
406 	g_return_val_if_fail (schema != NULL, FALSE);
407 	g_return_val_if_fail (label != NULL, FALSE);
408 	g_return_val_if_fail (password != NULL, FALSE);
409 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
410 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
411 
412 	va_start (va, error);
413 	attributes = secret_attributes_buildv (schema, va);
414 	va_end (va);
415 
416 	/* Precondition failed, already warned */
417 	if (!attributes)
418 		return FALSE;
419 
420 	ret = secret_password_storev_sync (schema, attributes, collection,
421 	                                   label, password, cancellable, error);
422 
423 	g_hash_table_unref (attributes);
424 	return ret;
425 }
426 
427 /**
428  * secret_password_storev_sync: (rename-to secret_password_store_sync)
429  * @schema: (nullable): the schema for attributes
430  * @attributes: (element-type utf8 utf8): the attribute keys and values
431  * @collection: (allow-none): a collection alias, or D-Bus object path of the collection where to store the secret
432  * @label: label for the secret
433  * @password: the null-terminated password to store
434  * @cancellable: optional cancellation object
435  * @error: location to place an error on failure
436  *
437  * Store a password in the secret service.
438  *
439  * The @attributes should be a set of key and value string pairs.
440  *
441  * If the attributes match a secret item already stored in the collection, then
442  * the item will be updated with these new values.
443  *
444  * If @collection is %NULL, then the default collection will be
445  * used. Use #SECRET_COLLECTION_SESSION to store the password in the session
446  * collection, which doesn't get stored across login sessions.
447  *
448  * This method may block indefinitely and should not be used in user interface
449  * threads.
450  *
451  * Returns: whether the storage was successful or not
452  */
453 gboolean
secret_password_storev_sync(const SecretSchema * schema,GHashTable * attributes,const gchar * collection,const gchar * label,const gchar * password,GCancellable * cancellable,GError ** error)454 secret_password_storev_sync (const SecretSchema *schema,
455                              GHashTable *attributes,
456                              const gchar *collection,
457                              const gchar *label,
458                              const gchar *password,
459                              GCancellable *cancellable,
460                              GError **error)
461 {
462 	SecretSync *sync;
463 	gboolean ret;
464 
465 	g_return_val_if_fail (label != NULL, FALSE);
466 	g_return_val_if_fail (password != NULL, FALSE);
467 	g_return_val_if_fail (attributes != NULL, FALSE);
468 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
469 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
470 
471 	/* Warnings raised already */
472 	if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE))
473 		return FALSE;
474 
475 	sync = _secret_sync_new ();
476 	g_main_context_push_thread_default (sync->context);
477 
478 	secret_password_storev (schema, attributes, collection, label, password,
479 	                        cancellable, _secret_sync_on_result, sync);
480 
481 	g_main_loop_run (sync->loop);
482 
483 	ret = secret_password_store_finish (sync->result, error);
484 
485 	g_main_context_pop_thread_default (sync->context);
486 	_secret_sync_free (sync);
487 
488 	return ret;
489 }
490 
491 /**
492  * secret_password_store_binary_sync:
493  * @schema: the schema for attributes
494  * @collection: (allow-none): a collection alias, or D-Bus object path of the collection where to store the secret
495  * @label: label for the secret
496  * @value: a #SecretValue
497  * @cancellable: optional cancellation object
498  * @error: location to place an error on failure
499  * @...: the attribute keys and values, terminated with %NULL
500  *
501  * Store a password in the secret service.
502  *
503  * This is similar to secret_password_store_sync(), but takes a
504  * #SecretValue as the argument instead of a null terminated password.
505  *
506  * This method may block indefinitely and should not be used in user interface
507  * threads.
508  *
509  * Returns: whether the storage was successful or not
510  *
511  * Since: 0.19.0
512  */
513 gboolean
secret_password_store_binary_sync(const SecretSchema * schema,const gchar * collection,const gchar * label,SecretValue * value,GCancellable * cancellable,GError ** error,...)514 secret_password_store_binary_sync (const SecretSchema *schema,
515 				   const gchar *collection,
516 				   const gchar *label,
517 				   SecretValue *value,
518 				   GCancellable *cancellable,
519 				   GError **error,
520 				   ...)
521 {
522 	GHashTable *attributes;
523 	va_list va;
524 	gboolean ret;
525 
526 	g_return_val_if_fail (schema != NULL, FALSE);
527 	g_return_val_if_fail (label != NULL, FALSE);
528 	g_return_val_if_fail (value != NULL, FALSE);
529 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
530 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
531 
532 	va_start (va, error);
533 	attributes = secret_attributes_buildv (schema, va);
534 	va_end (va);
535 
536 	/* Precondition failed, already warned */
537 	if (!attributes)
538 		return FALSE;
539 
540 	ret = secret_password_storev_binary_sync (schema, attributes, collection,
541 						  label, value, cancellable, error);
542 
543 	g_hash_table_unref (attributes);
544 	return ret;
545 }
546 
547 /**
548  * secret_password_storev_binary_sync: (rename-to secret_password_store_binary_sync)
549  * @schema: (nullable): the schema for attributes
550  * @attributes: (element-type utf8 utf8): the attribute keys and values
551  * @collection: (allow-none): a collection alias, or D-Bus object path of the collection where to store the secret
552  * @label: label for the secret
553  * @value: a #SecretValue
554  * @cancellable: optional cancellation object
555  * @error: location to place an error on failure
556  *
557  * Store a password in the secret service.
558  *
559  * This is similar to secret_password_storev_sync(), but takes a
560  * #SecretValue as the argument instead of a null-terminated passwords.
561  *
562  * This method may block indefinitely and should not be used in user interface
563  * threads.
564  *
565  * Returns: whether the storage was successful or not
566  *
567  * Since: 0.19.0
568  */
569 gboolean
secret_password_storev_binary_sync(const SecretSchema * schema,GHashTable * attributes,const gchar * collection,const gchar * label,SecretValue * value,GCancellable * cancellable,GError ** error)570 secret_password_storev_binary_sync (const SecretSchema *schema,
571 				    GHashTable *attributes,
572 				    const gchar *collection,
573 				    const gchar *label,
574 				    SecretValue *value,
575 				    GCancellable *cancellable,
576 				    GError **error)
577 {
578 	SecretSync *sync;
579 	gboolean ret;
580 
581 	g_return_val_if_fail (label != NULL, FALSE);
582 	g_return_val_if_fail (value != NULL, FALSE);
583 	g_return_val_if_fail (attributes != NULL, FALSE);
584 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
585 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
586 
587 	/* Warnings raised already */
588 	if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE))
589 		return FALSE;
590 
591 	sync = _secret_sync_new ();
592 	g_main_context_push_thread_default (sync->context);
593 
594 	secret_password_storev_binary (schema, attributes, collection, label, value,
595 				       cancellable, _secret_sync_on_result, sync);
596 
597 	g_main_loop_run (sync->loop);
598 
599 	ret = secret_password_store_finish (sync->result, error);
600 
601 	g_main_context_pop_thread_default (sync->context);
602 	_secret_sync_free (sync);
603 
604 	return ret;
605 }
606 
607 /**
608  * secret_password_lookup: (skip)
609  * @schema: the schema for the attributes
610  * @cancellable: optional cancellation object
611  * @callback: called when the operation completes
612  * @user_data: data to be passed to the callback
613  * @...: the attribute keys and values, terminated with %NULL
614  *
615  * Lookup a password in the secret service.
616  *
617  * The variable argument list should contain pairs of a) The attribute name as
618  * a null-terminated string, followed by b) attribute value, either a character
619  * string, an int number, or a gboolean value, as defined in the password
620  * @schema. The list of attribtues should be terminated with a %NULL.
621  *
622  * If no secret is found then %NULL is returned.
623  *
624  * This method will return immediately and complete asynchronously.
625  */
626 void
secret_password_lookup(const SecretSchema * schema,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data,...)627 secret_password_lookup (const SecretSchema *schema,
628                         GCancellable *cancellable,
629                         GAsyncReadyCallback callback,
630                         gpointer user_data,
631                         ...)
632 {
633 	GHashTable *attributes;
634 	va_list va;
635 
636 	g_return_if_fail (schema != NULL);
637 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
638 
639 	va_start (va, user_data);
640 	attributes = secret_attributes_buildv (schema, va);
641 	va_end (va);
642 
643 	/* Precondition failed, already warned */
644 	if (!attributes)
645 		return;
646 
647 	secret_password_lookupv (schema, attributes, cancellable,
648 	                         callback, user_data);
649 
650 	g_hash_table_unref (attributes);
651 }
652 
653 typedef struct {
654 	const SecretSchema *schema;
655 	GHashTable *attributes;
656 } LookupClosure;
657 
658 static void
lookup_closure_free(gpointer data)659 lookup_closure_free (gpointer data)
660 {
661 	LookupClosure *closure = data;
662 	_secret_schema_unref_if_nonstatic (closure->schema);
663 	g_hash_table_unref (closure->attributes);
664 	g_slice_free (LookupClosure, closure);
665 }
666 
667 static void
on_lookup(GObject * source,GAsyncResult * result,gpointer user_data)668 on_lookup (GObject *source,
669 	   GAsyncResult *result,
670 	   gpointer user_data)
671 {
672 	GTask *task = G_TASK (user_data);
673 	SecretBackend *backend = SECRET_BACKEND (source);
674 	SecretBackendInterface *iface;
675 	SecretValue *value;
676 	GError *error = NULL;
677 
678 	iface = SECRET_BACKEND_GET_IFACE (backend);
679 	g_return_if_fail (iface->store_finish != NULL);
680 
681 	value = iface->lookup_finish (backend, result, &error);
682 	if (error) {
683 		g_task_return_error (task, error);
684 		g_object_unref (task);
685 		return;
686 	}
687 
688 	if (value)
689 		g_task_return_pointer (task, value, secret_value_unref);
690 	else
691 		g_task_return_pointer (task, NULL, NULL);
692 	g_object_unref (task);
693 }
694 
695 static void
on_lookup_backend(GObject * source,GAsyncResult * result,gpointer user_data)696 on_lookup_backend (GObject *source,
697 		   GAsyncResult *result,
698 		   gpointer user_data)
699 {
700 	GTask *task = G_TASK (user_data);
701 	LookupClosure *lookup = g_task_get_task_data (task);
702 	SecretBackend *backend;
703 	SecretBackendInterface *iface;
704 	GError *error = NULL;
705 
706 	backend = secret_backend_get_finish (result, &error);
707 	if (backend == NULL) {
708 		g_task_return_error (task, error);
709 		g_object_unref (task);
710 		return;
711 	}
712 
713 	iface = SECRET_BACKEND_GET_IFACE (backend);
714 	g_return_if_fail (iface->store != NULL);
715 
716 	iface->lookup (backend, lookup->schema, lookup->attributes,
717 		       g_task_get_cancellable (task),
718 		       on_lookup,
719 		       task);
720 }
721 
722 /**
723  * secret_password_lookupv: (rename-to secret_password_lookup)
724  * @schema: (nullable): the schema for attributes
725  * @attributes: (element-type utf8 utf8) (transfer full): the attribute keys and values
726  * @cancellable: optional cancellation object
727  * @callback: (scope async): called when the operation completes
728  * @user_data: data to be passed to the callback
729  *
730  * Lookup a password in the secret service.
731  *
732  * The @attributes should be a set of key and value string pairs.
733  *
734  * If no secret is found then %NULL is returned.
735  *
736  * This method will return immediately and complete asynchronously.
737  */
738 void
secret_password_lookupv(const SecretSchema * schema,GHashTable * attributes,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)739 secret_password_lookupv (const SecretSchema *schema,
740                          GHashTable *attributes,
741                          GCancellable *cancellable,
742                          GAsyncReadyCallback callback,
743                          gpointer user_data)
744 {
745 	LookupClosure *lookup;
746 	GTask *task;
747 
748 	g_return_if_fail (attributes != NULL);
749 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
750 
751 	/* Warnings raised already */
752 	if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
753 		return;
754 
755 	task = g_task_new (NULL, cancellable, callback, user_data);
756 	lookup = g_slice_new0 (LookupClosure);
757 	lookup->schema = _secret_schema_ref_if_nonstatic (schema);
758 	lookup->attributes = g_hash_table_ref (attributes);
759 	g_task_set_task_data (task, lookup, lookup_closure_free);
760 
761 	secret_backend_get (SECRET_BACKEND_OPEN_SESSION,
762 			    cancellable,
763 			    on_lookup_backend, task);
764 }
765 
766 /**
767  * secret_password_lookup_nonpageable_finish: (skip)
768  * @result: the asynchronous result passed to the callback
769  * @error: location to place an error on failure
770  *
771  * Finish an asynchronous operation to lookup a password in the secret service.
772  *
773  * Returns: (transfer full): a new password string stored in nonpageable memory
774  *          which must be freed with secret_password_free() when done
775  */
776 gchar *
secret_password_lookup_nonpageable_finish(GAsyncResult * result,GError ** error)777 secret_password_lookup_nonpageable_finish (GAsyncResult *result,
778                                            GError **error)
779 {
780 	SecretValue *value;
781 
782 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
783 	g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
784 
785 	value = g_task_propagate_pointer (G_TASK (result), error);
786 	if (value == NULL)
787 		return NULL;
788 
789 	return _secret_value_unref_to_password (value);
790 }
791 
792 /**
793  * secret_password_lookup_binary_finish: (skip)
794  * @result: the asynchronous result passed to the callback
795  * @error: location to place an error on failure
796  *
797  * Finish an asynchronous operation to lookup a password in the secret service.
798  *
799  * Returns: (transfer full): a newly allocated #SecretValue, which should be
800  *          released with secret_value_unref(), or %NULL if no secret found
801  *
802  * Since: 0.19.0
803  */
804 SecretValue *
secret_password_lookup_binary_finish(GAsyncResult * result,GError ** error)805 secret_password_lookup_binary_finish (GAsyncResult *result,
806 				      GError **error)
807 {
808 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
809 	g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
810 
811 	return g_task_propagate_pointer (G_TASK (result), error);
812 }
813 
814 /**
815  * secret_password_lookup_finish:
816  * @result: the asynchronous result passed to the callback
817  * @error: location to place an error on failure
818  *
819  * Finish an asynchronous operation to lookup a password in the secret service.
820  *
821  * Returns: (transfer full): a new password string which should be freed with
822  *          secret_password_free() or may be freed with g_free() when done
823  */
824 gchar *
secret_password_lookup_finish(GAsyncResult * result,GError ** error)825 secret_password_lookup_finish (GAsyncResult *result,
826                                GError **error)
827 {
828 	SecretValue *value;
829 
830 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
831 	g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
832 
833 	value = g_task_propagate_pointer (G_TASK (result), error);
834 	if (value == NULL)
835 		return NULL;
836 
837 	return _secret_value_unref_to_string (value);
838 }
839 
840 /**
841  * secret_password_lookup_sync: (skip)
842  * @schema: the schema for the attributes
843  * @cancellable: optional cancellation object
844  * @error: location to place an error on failure
845  * @...: the attribute keys and values, terminated with %NULL
846  *
847  * Lookup a password in the secret service.
848  *
849  * The variable argument list should contain pairs of a) The attribute name as
850  * a null-terminated string, followed by b) attribute value, either a character
851  * string, an int number, or a gboolean value, as defined in the password
852  * @schema. The list of attributes should be terminated with a %NULL.
853  *
854  * If no secret is found then %NULL is returned.
855  *
856  * This method may block indefinitely and should not be used in user interface
857  * threads.
858  *
859  * Returns: (transfer full): a new password string which should be freed with
860  *          secret_password_free() or may be freed with g_free() when done
861  */
862 gchar *
secret_password_lookup_sync(const SecretSchema * schema,GCancellable * cancellable,GError ** error,...)863 secret_password_lookup_sync (const SecretSchema *schema,
864                              GCancellable *cancellable,
865                              GError **error,
866                              ...)
867 {
868 	GHashTable *attributes;
869 	gchar *password;
870 	va_list va;
871 
872 	g_return_val_if_fail (schema != NULL, NULL);
873 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
874 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
875 
876 	va_start (va, error);
877 	attributes = secret_attributes_buildv (schema, va);
878 	va_end (va);
879 
880 	/* Precondition failed, already warned */
881 	if (!attributes)
882 		return NULL;
883 
884 	password = secret_password_lookupv_sync (schema, attributes,
885 	                                         cancellable, error);
886 
887 	g_hash_table_unref (attributes);
888 
889 	return password;
890 }
891 
892 /**
893  * secret_password_lookup_nonpageable_sync: (skip)
894  * @schema: the schema for the attributes
895  * @cancellable: optional cancellation object
896  * @error: location to place an error on failure
897  * @...: the attribute keys and values, terminated with %NULL
898  *
899  * Lookup a password in the secret service.
900  *
901  * The variable argument list should contain pairs of a) The attribute name as
902  * a null-terminated string, followed by b) attribute value, either a character
903  * string, an int number, or a gboolean value, as defined in the password
904  * @schema. The list of attribtues should be terminated with a %NULL.
905  *
906  * If no secret is found then %NULL is returned.
907  *
908  * This method may block indefinitely and should not be used in user interface
909  * threads.
910  *
911  * Returns: (transfer full): a new password string stored in nonpageable memory
912  *          which must be freed with secret_password_free() when done
913  */
914 gchar *
secret_password_lookup_nonpageable_sync(const SecretSchema * schema,GCancellable * cancellable,GError ** error,...)915 secret_password_lookup_nonpageable_sync (const SecretSchema *schema,
916                                          GCancellable *cancellable,
917                                          GError **error,
918                                          ...)
919 {
920 	GHashTable *attributes;
921 	gchar *password;
922 	va_list va;
923 
924 	g_return_val_if_fail (schema != NULL, NULL);
925 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
926 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
927 
928 	va_start (va, error);
929 	attributes = secret_attributes_buildv (schema, va);
930 	va_end (va);
931 
932 	/* Precondition failed, already warned */
933 	if (!attributes)
934 		return NULL;
935 
936 	password = secret_password_lookupv_nonpageable_sync (schema, attributes,
937 	                                                     cancellable, error);
938 
939 	g_hash_table_unref (attributes);
940 
941 	return password;
942 }
943 
944 /**
945  * secret_password_lookupv_nonpageable_sync: (skip)
946  * @schema: (nullable): the schema for attributes
947  * @attributes: (element-type utf8 utf8): the attribute keys and values
948  * @cancellable: optional cancellation object
949  * @error: location to place an error on failure
950  *
951  * Lookup a password in the secret service.
952  *
953  * The @attributes should be a set of key and value string pairs.
954  *
955  * If no secret is found then %NULL is returned.
956  *
957  * This method may block indefinitely and should not be used in user interface
958  * threads.
959  *
960  * Returns: (transfer full): a new password string stored in non pageable memory
961  *          which should be freed with secret_password_free() when done
962  */
963 gchar *
secret_password_lookupv_nonpageable_sync(const SecretSchema * schema,GHashTable * attributes,GCancellable * cancellable,GError ** error)964 secret_password_lookupv_nonpageable_sync (const SecretSchema *schema,
965                                           GHashTable *attributes,
966                                           GCancellable *cancellable,
967                                           GError **error)
968 {
969 	SecretSync *sync;
970 	gchar *password;
971 
972 	g_return_val_if_fail (attributes != NULL, NULL);
973 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
974 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
975 
976 	/* Warnings raised already */
977 	if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
978 		return FALSE;
979 
980 	sync = _secret_sync_new ();
981 	g_main_context_push_thread_default (sync->context);
982 
983 	secret_password_lookupv (schema, attributes, cancellable,
984 	                         _secret_sync_on_result, sync);
985 
986 	g_main_loop_run (sync->loop);
987 
988 	password = secret_password_lookup_nonpageable_finish (sync->result, error);
989 
990 	g_main_context_pop_thread_default (sync->context);
991 	_secret_sync_free (sync);
992 
993 	return password;
994 }
995 
996 /**
997  * secret_password_lookup_binary_sync: (skip)
998  * @schema: the schema for the attributes
999  * @cancellable: optional cancellation object
1000  * @error: location to place an error on failure
1001  * @...: the attribute keys and values, terminated with %NULL
1002  *
1003  * Lookup a password in the secret service.
1004  *
1005  * This is similar to secret_password_lookup_sync(), but returns a
1006  * #SecretValue instead of a null-terminated password.
1007  *
1008  * This method may block indefinitely and should not be used in user interface
1009  * threads.
1010  *
1011  * Returns: (transfer full): a newly allocated #SecretValue, which should be
1012  *          released with secret_value_unref(), or %NULL if no secret found
1013  *
1014  * Since: 0.19.0
1015  */
1016 SecretValue *
secret_password_lookup_binary_sync(const SecretSchema * schema,GCancellable * cancellable,GError ** error,...)1017 secret_password_lookup_binary_sync (const SecretSchema *schema,
1018 				    GCancellable *cancellable,
1019 				    GError **error,
1020 				    ...)
1021 {
1022 	GHashTable *attributes;
1023 	SecretValue *value;
1024 	va_list va;
1025 
1026 	g_return_val_if_fail (schema != NULL, NULL);
1027 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
1028 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1029 
1030 	va_start (va, error);
1031 	attributes = secret_attributes_buildv (schema, va);
1032 	va_end (va);
1033 
1034 	/* Precondition failed, already warned */
1035 	if (!attributes)
1036 		return NULL;
1037 
1038 	value = secret_password_lookupv_binary_sync (schema, attributes,
1039 						     cancellable, error);
1040 
1041 	g_hash_table_unref (attributes);
1042 
1043 	return value;
1044 }
1045 
1046 /**
1047  * secret_password_lookupv_binary_sync: (skip)
1048  * @schema: (nullable): the schema for attributes
1049  * @attributes: (element-type utf8 utf8): the attribute keys and values
1050  * @cancellable: optional cancellation object
1051  * @error: location to place an error on failure
1052  *
1053  * Lookup a password in the secret service.
1054  *
1055  * This is similar to secret_password_lookupv_sync(), but returns a
1056  * #SecretValue instead of a null-terminated password.
1057  *
1058  * This method may block indefinitely and should not be used in user interface
1059  * threads.
1060  *
1061  * Returns: (transfer full): a newly allocated #SecretValue, which should be
1062  *          released with secret_value_unref(), or %NULL if no secret found
1063  *
1064  * Since: 0.19.0
1065  */
1066 SecretValue *
secret_password_lookupv_binary_sync(const SecretSchema * schema,GHashTable * attributes,GCancellable * cancellable,GError ** error)1067 secret_password_lookupv_binary_sync (const SecretSchema *schema,
1068 				     GHashTable *attributes,
1069 				     GCancellable *cancellable,
1070 				     GError **error)
1071 {
1072 	SecretSync *sync;
1073 	SecretValue *value;
1074 
1075 	g_return_val_if_fail (attributes != NULL, NULL);
1076 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
1077 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1078 
1079 	/* Warnings raised already */
1080 	if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
1081 		return FALSE;
1082 
1083 	sync = _secret_sync_new ();
1084 	g_main_context_push_thread_default (sync->context);
1085 
1086 	secret_password_lookupv (schema, attributes, cancellable,
1087 	                         _secret_sync_on_result, sync);
1088 
1089 	g_main_loop_run (sync->loop);
1090 
1091 	value = secret_password_lookup_binary_finish (sync->result, error);
1092 
1093 	g_main_context_pop_thread_default (sync->context);
1094 	_secret_sync_free (sync);
1095 
1096 	return value;
1097 }
1098 
1099 /**
1100  * secret_password_lookupv_sync: (rename-to secret_password_lookup_sync)
1101  * @schema: (nullable): the schema for attributes
1102  * @attributes: (element-type utf8 utf8): the attribute keys and values
1103  * @cancellable: optional cancellation object
1104  * @error: location to place an error on failure
1105  *
1106  * Lookup a password in the secret service.
1107  *
1108  * The @attributes should be a set of key and value string pairs.
1109  *
1110  * If no secret is found then %NULL is returned.
1111  *
1112  * This method may block indefinitely and should not be used in user interface
1113  * threads.
1114  *
1115  * Returns: (transfer full): a new password string which should be freed with
1116  *          secret_password_free() or may be freed with g_free() when done
1117  */
1118 gchar *
secret_password_lookupv_sync(const SecretSchema * schema,GHashTable * attributes,GCancellable * cancellable,GError ** error)1119 secret_password_lookupv_sync (const SecretSchema *schema,
1120                               GHashTable *attributes,
1121                               GCancellable *cancellable,
1122                               GError **error)
1123 {
1124 	SecretSync *sync;
1125 	gchar *string;
1126 
1127 	g_return_val_if_fail (attributes != NULL, NULL);
1128 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
1129 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1130 
1131 	/* Warnings raised already */
1132 	if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
1133 		return FALSE;
1134 
1135 	sync = _secret_sync_new ();
1136 	g_main_context_push_thread_default (sync->context);
1137 
1138 	secret_password_lookupv (schema, attributes, cancellable,
1139 	                         _secret_sync_on_result, sync);
1140 
1141 	g_main_loop_run (sync->loop);
1142 
1143 	string = secret_password_lookup_finish (sync->result, error);
1144 
1145 	g_main_context_pop_thread_default (sync->context);
1146 	_secret_sync_free (sync);
1147 
1148 	return string;
1149 }
1150 
1151 /**
1152  * secret_password_clear:
1153  * @schema: the schema for the attributes
1154  * @cancellable: optional cancellation object
1155  * @callback: called when the operation completes
1156  * @user_data: data to be passed to the callback
1157  * @...: the attribute keys and values, terminated with %NULL
1158  *
1159  * Clear unlocked matching passwords from the secret service.
1160  *
1161  * The variable argument list should contain pairs of a) The attribute name as
1162  * a null-terminated string, followed by b) attribute value, either a character
1163  * string, an int number, or a gboolean value, as defined in the password
1164  * @schema. The list of attribtues should be terminated with a %NULL.
1165  *
1166  * All unlocked items that match the attributes will be deleted.
1167  *
1168  * This method will return immediately and complete asynchronously.
1169  */
1170 void
secret_password_clear(const SecretSchema * schema,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data,...)1171 secret_password_clear (const SecretSchema *schema,
1172                        GCancellable *cancellable,
1173                        GAsyncReadyCallback callback,
1174                        gpointer user_data,
1175                        ...)
1176 {
1177 	GHashTable *attributes;
1178 	va_list va;
1179 
1180 	g_return_if_fail (schema != NULL);
1181 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1182 
1183 	va_start (va, user_data);
1184 	attributes = secret_attributes_buildv (schema, va);
1185 	va_end (va);
1186 
1187 	/* Precondition failed, already warned */
1188 	if (!attributes)
1189 		return;
1190 
1191 	secret_password_clearv (schema, attributes, cancellable,
1192 	                        callback, user_data);
1193 
1194 	g_hash_table_unref (attributes);
1195 }
1196 
1197 typedef struct {
1198 	const SecretSchema *schema;
1199 	GHashTable *attributes;
1200 } ClearClosure;
1201 
1202 static void
clear_closure_free(gpointer data)1203 clear_closure_free (gpointer data)
1204 {
1205 	ClearClosure *closure = data;
1206 	_secret_schema_unref_if_nonstatic (closure->schema);
1207 	g_hash_table_unref (closure->attributes);
1208 	g_slice_free (ClearClosure, closure);
1209 }
1210 
1211 static void
on_clear(GObject * source,GAsyncResult * result,gpointer user_data)1212 on_clear (GObject *source,
1213 	  GAsyncResult *result,
1214 	  gpointer user_data)
1215 {
1216 	GTask *task = G_TASK (user_data);
1217 	SecretBackend *backend = SECRET_BACKEND (source);
1218 	SecretBackendInterface *iface;
1219 	GError *error = NULL;
1220 
1221 	iface = SECRET_BACKEND_GET_IFACE (backend);
1222 	g_return_if_fail (iface->clear_finish != NULL);
1223 
1224 	if (!iface->clear_finish (backend, result, &error)) {
1225 		if (error)
1226 			g_task_return_error (task, error);
1227 		else
1228 			g_task_return_boolean (task, FALSE);
1229 		g_object_unref (task);
1230 		return;
1231 	}
1232 
1233 	g_task_return_boolean (task, TRUE);
1234 	g_object_unref (task);
1235 }
1236 
1237 static void
on_clear_backend(GObject * source,GAsyncResult * result,gpointer user_data)1238 on_clear_backend (GObject *source,
1239 		  GAsyncResult *result,
1240 		  gpointer user_data)
1241 {
1242 	GTask *task = G_TASK (user_data);
1243 	ClearClosure *clear = g_task_get_task_data (task);
1244 	SecretBackend *backend;
1245 	SecretBackendInterface *iface;
1246 	GError *error = NULL;
1247 
1248 	backend = secret_backend_get_finish (result, &error);
1249 	if (backend == NULL) {
1250 		g_task_return_error (task, error);
1251 		g_object_unref (task);
1252 		return;
1253 	}
1254 
1255 	iface = SECRET_BACKEND_GET_IFACE (backend);
1256 	g_return_if_fail (iface->clear != NULL);
1257 
1258 	iface->clear (backend, clear->schema, clear->attributes,
1259 		      g_task_get_cancellable (task),
1260 		      on_clear,
1261 		      task);
1262 }
1263 
1264 /**
1265  * secret_password_clearv: (rename-to secret_password_clear)
1266  * @schema: (nullable): the schema for the attributes
1267  * @attributes: (element-type utf8 utf8) (transfer full): the attribute keys and values
1268  * @cancellable: optional cancellation object
1269  * @callback: (scope async): called when the operation completes
1270  * @user_data: data to be passed to the callback
1271  *
1272  * Remove unlocked matching passwords from the secret service.
1273  *
1274  * The @attributes should be a set of key and value string pairs.
1275  *
1276  * All unlocked items that match the attributes will be deleted.
1277  *
1278  * This method will return immediately and complete asynchronously.
1279  */
1280 void
secret_password_clearv(const SecretSchema * schema,GHashTable * attributes,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1281 secret_password_clearv (const SecretSchema *schema,
1282                         GHashTable *attributes,
1283                         GCancellable *cancellable,
1284                         GAsyncReadyCallback callback,
1285                         gpointer user_data)
1286 {
1287 	ClearClosure *clear;
1288 	GTask *task;
1289 
1290 	g_return_if_fail (attributes != NULL);
1291 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1292 
1293 	/* Warnings raised already */
1294 	if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
1295 		return;
1296 
1297 	task = g_task_new (NULL, cancellable, callback, user_data);
1298 	clear = g_slice_new0 (ClearClosure);
1299 	clear->schema = _secret_schema_ref_if_nonstatic (schema);
1300 	clear->attributes = g_hash_table_ref (attributes);
1301 	g_task_set_task_data (task, clear, clear_closure_free);
1302 
1303 	secret_backend_get (SECRET_SERVICE_NONE,
1304 			    cancellable,
1305 			    on_clear_backend, task);
1306 }
1307 
1308 /**
1309  * secret_password_clear_finish:
1310  * @result: the asynchronous result passed to the callback
1311  * @error: location to place an error on failure
1312  *
1313  * Finish an asynchronous operation to remove passwords from the secret
1314  * service.
1315  *
1316  * Returns: whether any passwords were removed
1317  */
1318 gboolean
secret_password_clear_finish(GAsyncResult * result,GError ** error)1319 secret_password_clear_finish (GAsyncResult *result,
1320                               GError **error)
1321 {
1322 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1323 	g_return_val_if_fail (g_task_is_valid (result, NULL), FALSE);
1324 
1325 	return g_task_propagate_boolean (G_TASK (result), error);
1326 }
1327 
1328 /**
1329  * secret_password_clear_sync:
1330  * @schema: the schema for the attributes
1331  * @cancellable: optional cancellation object
1332  * @error: location to place an error on failure
1333  * @...: the attribute keys and values, terminated with %NULL
1334  *
1335  * Remove unlocked matching passwords from the secret service.
1336  *
1337  * The variable argument list should contain pairs of a) The attribute name as
1338  * a null-terminated string, followed by b) attribute value, either a character
1339  * string, an int number, or a gboolean value, as defined in the password
1340  * @schema. The list of attribtues should be terminated with a %NULL.
1341  *
1342  * All unlocked items that match the attributes will be deleted.
1343  *
1344  * This method may block indefinitely and should not be used in user interface
1345  * threads.
1346  *
1347  * Returns: whether the any passwords were removed
1348  */
1349 gboolean
secret_password_clear_sync(const SecretSchema * schema,GCancellable * cancellable,GError ** error,...)1350 secret_password_clear_sync (const SecretSchema* schema,
1351                             GCancellable *cancellable,
1352                             GError **error,
1353                             ...)
1354 {
1355 	GHashTable *attributes;
1356 	gboolean result;
1357 	va_list va;
1358 
1359 	g_return_val_if_fail (schema != NULL, FALSE);
1360 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1361 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1362 
1363 	va_start (va, error);
1364 	attributes = secret_attributes_buildv (schema, va);
1365 	va_end (va);
1366 
1367 	/* Precondition failed, already warned */
1368 	if (!attributes)
1369 		return FALSE;
1370 
1371 	result = secret_password_clearv_sync (schema, attributes,
1372 	                                      cancellable, error);
1373 
1374 	g_hash_table_unref (attributes);
1375 
1376 	return result;
1377 }
1378 
1379 /**
1380  * secret_password_clearv_sync: (rename-to secret_password_clear_sync)
1381  * @schema: (nullable): the schema for the attributes
1382  * @attributes: (element-type utf8 utf8): the attribute keys and values
1383  * @cancellable: optional cancellation object
1384  * @error: location to place an error on failure
1385  *
1386  * Remove unlocked matching passwords from the secret service.
1387  *
1388  * The @attributes should be a set of key and value string pairs.
1389  *
1390  * All unlocked items that match the attributes will be deleted.
1391  *
1392  * This method may block indefinitely and should not be used in user interface
1393  * threads.
1394  *
1395  * Returns: whether any passwords were removed
1396  */
1397 gboolean
secret_password_clearv_sync(const SecretSchema * schema,GHashTable * attributes,GCancellable * cancellable,GError ** error)1398 secret_password_clearv_sync (const SecretSchema *schema,
1399                              GHashTable *attributes,
1400                              GCancellable *cancellable,
1401                              GError **error)
1402 {
1403 	SecretSync *sync;
1404 	gboolean result;
1405 
1406 	g_return_val_if_fail (attributes != NULL, FALSE);
1407 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1408 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1409 
1410 	/* Warnings raised already */
1411 	if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
1412 		return FALSE;
1413 
1414 	sync = _secret_sync_new ();
1415 	g_main_context_push_thread_default (sync->context);
1416 
1417 	secret_password_clearv (schema, attributes, cancellable,
1418 	                        _secret_sync_on_result, sync);
1419 
1420 	g_main_loop_run (sync->loop);
1421 
1422 	result = secret_password_clear_finish (sync->result, error);
1423 
1424 	g_main_context_pop_thread_default (sync->context);
1425 	_secret_sync_free (sync);
1426 
1427 	return result;
1428 }
1429 
1430 /**
1431  * secret_password_search: (skip)
1432  * @schema: the schema for the attributes
1433  * @flags: search option flags
1434  * @cancellable: optional cancellation object
1435  * @callback: called when the operation completes
1436  * @user_data: data to be passed to the callback
1437  * @...: the attribute keys and values, terminated with %NULL
1438  *
1439  * Search for items in the secret service.
1440  *
1441  * The variable argument list should contain pairs of a) The attribute name as
1442  * a null-terminated string, followed by b) attribute value, either a character
1443  * string, an int number, or a gboolean value, as defined in the password
1444  * @schema. The list of attribtues should be terminated with a %NULL.
1445  *
1446  * This method will return immediately and complete asynchronously.
1447  *
1448  * Since: 0.19.0
1449  */
1450 void
secret_password_search(const SecretSchema * schema,SecretSearchFlags flags,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data,...)1451 secret_password_search (const SecretSchema *schema,
1452                         SecretSearchFlags flags,
1453                         GCancellable *cancellable,
1454                         GAsyncReadyCallback callback,
1455                         gpointer user_data,
1456                         ...)
1457 {
1458         GHashTable *attributes;
1459         va_list va;
1460 
1461         g_return_if_fail (schema != NULL);
1462         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1463 
1464         va_start (va, user_data);
1465         attributes = secret_attributes_buildv (schema, va);
1466         va_end (va);
1467 
1468         /* Precondition failed, already warned */
1469         if (!attributes)
1470                 return;
1471 
1472         secret_password_searchv (schema, attributes, flags, cancellable,
1473                                  callback, user_data);
1474 
1475         g_hash_table_unref (attributes);
1476 }
1477 
1478 typedef struct {
1479 	const SecretSchema *schema;
1480 	GHashTable *attributes;
1481 	SecretSearchFlags flags;
1482 } SearchClosure;
1483 
1484 static void
search_closure_free(gpointer data)1485 search_closure_free (gpointer data)
1486 {
1487 	SearchClosure *closure = data;
1488 	_secret_schema_unref_if_nonstatic (closure->schema);
1489 	g_hash_table_unref (closure->attributes);
1490 	g_slice_free (SearchClosure, closure);
1491 }
1492 
1493 static void
object_list_free(gpointer data)1494 object_list_free (gpointer data)
1495 {
1496 	GList *list = data;
1497 	g_list_free_full (list, g_object_unref);
1498 }
1499 
1500 static void
on_search(GObject * source,GAsyncResult * result,gpointer user_data)1501 on_search (GObject *source,
1502 	   GAsyncResult *result,
1503 	   gpointer user_data)
1504 {
1505 	GTask *task = G_TASK (user_data);
1506 	SecretBackend *backend = SECRET_BACKEND (source);
1507 	SecretBackendInterface *iface;
1508 	GError *error = NULL;
1509 	GList *items;
1510 
1511 	iface = SECRET_BACKEND_GET_IFACE (backend);
1512 	g_return_if_fail (iface->search_finish != NULL);
1513 
1514 	items = iface->search_finish (backend, result, &error);
1515 	if (error) {
1516 		g_task_return_error (task, error);
1517 		g_object_unref (task);
1518 		return;
1519 	}
1520 
1521 	g_task_return_pointer (task, items, object_list_free);
1522 	g_object_unref (task);
1523 }
1524 
1525 static void
on_search_backend(GObject * source,GAsyncResult * result,gpointer user_data)1526 on_search_backend (GObject *source,
1527 		   GAsyncResult *result,
1528 		   gpointer user_data)
1529 {
1530 	GTask *task = G_TASK (user_data);
1531 	SearchClosure *search = g_task_get_task_data (task);
1532 	SecretBackend *backend;
1533 	SecretBackendInterface *iface;
1534 	GError *error = NULL;
1535 
1536 	backend = secret_backend_get_finish (result, &error);
1537 	if (backend == NULL) {
1538 		g_task_return_error (task, error);
1539 		g_object_unref (task);
1540 		return;
1541 	}
1542 
1543 	iface = SECRET_BACKEND_GET_IFACE (backend);
1544 	g_return_if_fail (iface->search != NULL);
1545 
1546 	iface->search (backend,
1547 		       search->schema, search->attributes, search->flags,
1548 		       g_task_get_cancellable (task),
1549 		       on_search,
1550 		       task);
1551 }
1552 
1553 /**
1554  * secret_password_searchv: (rename-to secret_password_search)
1555  * @schema: (nullable): the schema for attributes
1556  * @attributes: (element-type utf8 utf8) (transfer full): the attribute keys and values
1557  * @flags: search option flags
1558  * @cancellable: optional cancellation object
1559  * @callback: (scope async): called when the operation completes
1560  * @user_data: data to be passed to the callback
1561  *
1562  * Search for items in the secret service.
1563  *
1564  * The @attributes should be a set of key and value string pairs.
1565  *
1566  * This method will return immediately and complete asynchronously.
1567  *
1568  * Since: 0.19.0
1569  */
1570 void
secret_password_searchv(const SecretSchema * schema,GHashTable * attributes,SecretSearchFlags flags,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1571 secret_password_searchv (const SecretSchema *schema,
1572                          GHashTable *attributes,
1573                          SecretSearchFlags flags,
1574                          GCancellable *cancellable,
1575                          GAsyncReadyCallback callback,
1576                          gpointer user_data)
1577 {
1578 	SearchClosure *search;
1579 	GTask *task;
1580 
1581         g_return_if_fail (attributes != NULL);
1582         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1583 
1584         /* Warnings raised already */
1585         if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
1586                 return;
1587 
1588 	task = g_task_new (NULL, cancellable, callback, user_data);
1589 	search = g_slice_new0 (SearchClosure);
1590 	search->schema = _secret_schema_ref_if_nonstatic (schema);
1591 	search->attributes = g_hash_table_ref (attributes);
1592 	search->flags = flags;
1593 	g_task_set_task_data (task, search, search_closure_free);
1594 
1595         secret_backend_get (SECRET_SERVICE_NONE,
1596 			    cancellable,
1597 			    on_search_backend, task);
1598 }
1599 
1600 /**
1601  * secret_password_search_finish:
1602  * @result: the asynchronous result passed to the callback
1603  * @error: location to place an error on failure
1604  *
1605  * Finish an asynchronous operation to search for items in the secret service.
1606  *
1607  * Returns: (transfer full) (element-type Secret.Retrievable): a list of
1608  *          #SecretRetrievable containing attributes of the matched items
1609  *
1610  * Since: 0.19.0
1611  */
1612 GList *
secret_password_search_finish(GAsyncResult * result,GError ** error)1613 secret_password_search_finish (GAsyncResult *result,
1614                                GError **error)
1615 {
1616         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1617         g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
1618 
1619         return g_task_propagate_pointer (G_TASK (result), error);
1620 }
1621 
1622 /**
1623  * secret_password_search_sync: (skip)
1624  * @schema: the schema for the attributes
1625  * @flags: search option flags
1626  * @cancellable: optional cancellation object
1627  * @error: location to place an error on failure
1628  * @...: the attribute keys and values, terminated with %NULL
1629  *
1630  * Search for items in the secret service.
1631  *
1632  * The variable argument list should contain pairs of a) The attribute name as
1633  * a null-terminated string, followed by b) attribute value, either a character
1634  * string, an int number, or a gboolean value, as defined in the password
1635  * @schema. The list of attributes should be terminated with a %NULL.
1636  *
1637  * If no secret is found then %NULL is returned.
1638  *
1639  * This method may block indefinitely and should not be used in user interface
1640  * threads.
1641  *
1642  * Returns: (transfer full) (element-type Secret.Retrievable): a list of
1643  *          #SecretRetrievable containing attributes of the matched items
1644  *
1645  * Since: 0.19.0
1646  */
1647 GList *
secret_password_search_sync(const SecretSchema * schema,SecretSearchFlags flags,GCancellable * cancellable,GError ** error,...)1648 secret_password_search_sync (const SecretSchema *schema,
1649                              SecretSearchFlags flags,
1650                              GCancellable *cancellable,
1651                              GError **error,
1652                              ...)
1653 {
1654         GHashTable *attributes;
1655         GList *items;
1656         va_list va;
1657 
1658         g_return_val_if_fail (schema != NULL, NULL);
1659         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
1660         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1661 
1662         va_start (va, error);
1663         attributes = secret_attributes_buildv (schema, va);
1664         va_end (va);
1665 
1666         /* Precondition failed, already warned */
1667         if (!attributes)
1668                 return NULL;
1669 
1670         items = secret_password_searchv_sync (schema, attributes, flags,
1671                                               cancellable, error);
1672 
1673         g_hash_table_unref (attributes);
1674 
1675         return items;
1676 }
1677 
1678 /**
1679  * secret_password_searchv_sync: (rename-to secret_password_search_sync)
1680  * @schema: (nullable): the schema for attributes
1681  * @attributes: (element-type utf8 utf8): the attribute keys and values
1682  * @flags: search option flags
1683  * @cancellable: optional cancellation object
1684  * @error: location to place an error on failure
1685  *
1686  * Search for items in the secret service.
1687  *
1688  * The @attributes should be a set of key and value string pairs.
1689  *
1690  * If no secret is found then %NULL is returned.
1691  *
1692  * This method may block indefinitely and should not be used in user interface
1693  * threads.
1694  *
1695  * Returns: (transfer full) (element-type Secret.Retrievable): a list of
1696  *          #SecretRetrievable containing attributes of the matched items
1697  *
1698  * Since: 0.19.0
1699  */
1700 GList *
secret_password_searchv_sync(const SecretSchema * schema,GHashTable * attributes,SecretSearchFlags flags,GCancellable * cancellable,GError ** error)1701 secret_password_searchv_sync (const SecretSchema *schema,
1702                               GHashTable *attributes,
1703                               SecretSearchFlags flags,
1704                               GCancellable *cancellable,
1705                               GError **error)
1706 {
1707         SecretSync *sync;
1708         GList *items;
1709 
1710         g_return_val_if_fail (attributes != NULL, NULL);
1711         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
1712         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1713 
1714         /* Warnings raised already */
1715         if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
1716                 return NULL;
1717 
1718         sync = _secret_sync_new ();
1719         g_main_context_push_thread_default (sync->context);
1720 
1721         secret_password_searchv (schema, attributes, flags, cancellable,
1722                                  _secret_sync_on_result, sync);
1723 
1724         g_main_loop_run (sync->loop);
1725 
1726         items = secret_password_search_finish (sync->result, error);
1727 
1728         g_main_context_pop_thread_default (sync->context);
1729         _secret_sync_free (sync);
1730 
1731         return items;
1732 }
1733 
1734 /**
1735  * secret_password_free: (skip)
1736  * @password: (allow-none): password to free
1737  *
1738  * Clear the memory used by a password, and then free it.
1739  *
1740  * This function must be used to free nonpageable memory returned by
1741  * secret_password_lookup_nonpageable_finish(),
1742  * secret_password_lookup_nonpageable_sync() or
1743  * secret_password_lookupv_nonpageable_sync().
1744  */
1745 void
secret_password_free(gchar * password)1746 secret_password_free (gchar *password)
1747 {
1748 	if (password == NULL)
1749 		return;
1750 
1751 	egg_secure_strfree (password);
1752 }
1753 
1754 /**
1755  * secret_password_wipe:
1756  * @password: (allow-none): password to clear
1757  *
1758  * Clear the memory used by a password.
1759  */
1760 void
secret_password_wipe(gchar * password)1761 secret_password_wipe (gchar *password)
1762 {
1763 	if (password == NULL)
1764 		return;
1765 
1766 	egg_secure_strclear (password);
1767 }
1768