Some more documentation of the collection
[platform/upstream/libsecret.git] / library / gsecret-password.c
1 /* GSecret - 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 of the licence or (at
8  * your option) any later version.
9  *
10  * See the included COPYING file for more information.
11  */
12
13 #include "config.h"
14
15 #include "gsecret-password.h"
16 #include "gsecret-private.h"
17 #include "gsecret-value.h"
18
19 #include <egg/egg-secure-memory.h>
20
21 typedef struct {
22         const GSecretSchema *schema;
23         GHashTable *attributes;
24         gchar *collection_path;
25         gchar *label;
26         GSecretValue *value;
27         GCancellable *cancellable;
28         gboolean created;
29 } StoreClosure;
30
31 static void
32 store_closure_free (gpointer data)
33 {
34         StoreClosure *closure = data;
35         g_hash_table_unref (closure->attributes);
36         g_free (closure->collection_path);
37         g_free (closure->label);
38         gsecret_value_unref (closure->value);
39         g_clear_object (&closure->cancellable);
40         g_slice_free (StoreClosure, closure);
41 }
42
43 static void
44 on_store_complete (GObject *source,
45                    GAsyncResult *result,
46                    gpointer user_data)
47 {
48         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
49         StoreClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
50         GError *error = NULL;
51
52         closure->created = gsecret_service_store_finish (GSECRET_SERVICE (source),
53                                                          result, &error);
54         if (error != NULL)
55                 g_simple_async_result_take_error (res, error);
56
57         g_simple_async_result_complete (res);
58         g_object_unref (res);
59 }
60
61 static void
62 on_store_connected (GObject *source,
63                     GAsyncResult *result,
64                     gpointer user_data)
65 {
66         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
67         StoreClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
68         GSecretService *service;
69         GError *error = NULL;
70
71         service = gsecret_service_get_finish (result, &error);
72         if (error == NULL) {
73                 gsecret_service_storev (service, closure->schema,
74                                         closure->attributes,
75                                         closure->collection_path,
76                                         closure->label, closure->value,
77                                         closure->cancellable,
78                                         on_store_complete,
79                                         g_object_ref (res));
80                 g_object_unref (service);
81
82         } else {
83                 g_simple_async_result_take_error (res, error);
84                 g_simple_async_result_complete (res);
85         }
86
87         g_object_unref (res);
88 }
89
90 void
91 gsecret_password_store (const GSecretSchema *schema,
92                         const gchar *collection_path,
93                         const gchar *label,
94                         const gchar *password,
95                         GCancellable *cancellable,
96                         GAsyncReadyCallback callback,
97                         gpointer user_data,
98                         ...)
99 {
100         GHashTable *attributes;
101         va_list va;
102
103         g_return_if_fail (schema != NULL);
104         g_return_if_fail (collection_path != NULL);
105         g_return_if_fail (label != NULL);
106         g_return_if_fail (password != NULL);
107         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
108
109         va_start (va, user_data);
110         attributes = _gsecret_util_attributes_for_varargs (schema, va);
111         va_end (va);
112
113         gsecret_password_storev (schema, collection_path, label, password, attributes,
114                                  cancellable, callback, user_data);
115
116         g_hash_table_unref (attributes);
117 }
118
119 void
120 gsecret_password_storev (const GSecretSchema *schema,
121                          const gchar *collection_path,
122                          const gchar *label,
123                          const gchar *password,
124                          GHashTable *attributes,
125                          GCancellable *cancellable,
126                          GAsyncReadyCallback callback,
127                          gpointer user_data)
128 {
129         GSimpleAsyncResult *res;
130         StoreClosure *closure;
131
132         g_return_if_fail (schema != NULL);
133         g_return_if_fail (collection_path != NULL);
134         g_return_if_fail (label != NULL);
135         g_return_if_fail (password != NULL);
136         g_return_if_fail (attributes != NULL);
137         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
138
139         res = g_simple_async_result_new (NULL, callback, user_data,
140                                          gsecret_password_storev);
141         closure = g_slice_new0 (StoreClosure);
142         closure->schema = schema;
143         closure->collection_path = g_strdup (collection_path);
144         closure->label = g_strdup (label);
145         closure->value = gsecret_value_new (password, -1, "text/plain");
146         closure->attributes = g_hash_table_ref (attributes);
147         closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
148         g_simple_async_result_set_op_res_gpointer (res, closure, store_closure_free);
149
150         gsecret_service_get (GSECRET_SERVICE_OPEN_SESSION, cancellable,
151                              on_store_connected, g_object_ref (res));
152
153         g_object_unref (res);
154 }
155
156 gboolean
157 gsecret_password_store_finish (GAsyncResult *result,
158                                GError **error)
159 {
160         GSimpleAsyncResult *res;
161         StoreClosure *closure;
162
163         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
164         g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
165                               gsecret_password_storev), FALSE);
166
167         res = G_SIMPLE_ASYNC_RESULT (result);
168         if (g_simple_async_result_propagate_error (res, error))
169                 return FALSE;
170
171         closure = g_simple_async_result_get_op_res_gpointer (res);
172         return closure->created;
173 }
174
175 gboolean
176 gsecret_password_store_sync (const GSecretSchema *schema,
177                              const gchar *collection_path,
178                              const gchar *label,
179                              const gchar *password,
180                              GCancellable *cancellable,
181                              GError **error,
182                              ...)
183 {
184         GHashTable *attributes;
185         va_list va;
186         gboolean ret;
187
188         g_return_val_if_fail (schema != NULL, FALSE);
189         g_return_val_if_fail (label != NULL, FALSE);
190         g_return_val_if_fail (password != NULL, FALSE);
191         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
192         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
193
194         va_start (va, error);
195         attributes = _gsecret_util_attributes_for_varargs (schema, va);
196         va_end (va);
197
198         ret = gsecret_password_storev_sync (schema, collection_path, label, password,
199                                             attributes, cancellable, error);
200
201         g_hash_table_unref (attributes);
202         return ret;
203 }
204
205 gboolean
206 gsecret_password_storev_sync (const GSecretSchema *schema,
207                               const gchar *collection_path,
208                               const gchar *label,
209                               const gchar *password,
210                               GHashTable *attributes,
211                               GCancellable *cancellable,
212                               GError **error)
213 {
214         GSecretSync *sync;
215         gboolean ret;
216
217         g_return_val_if_fail (schema != NULL, FALSE);
218         g_return_val_if_fail (collection_path != NULL, FALSE);
219         g_return_val_if_fail (label != NULL, FALSE);
220         g_return_val_if_fail (password != NULL, FALSE);
221         g_return_val_if_fail (attributes != NULL, FALSE);
222         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
223         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
224
225         sync = _gsecret_sync_new ();
226         g_main_context_push_thread_default (sync->context);
227
228         gsecret_password_storev (schema, collection_path, label, password, attributes,
229                                  cancellable, _gsecret_sync_on_result, sync);
230
231         g_main_loop_run (sync->loop);
232
233         ret = gsecret_password_store_finish (sync->result, error);
234
235         g_main_context_pop_thread_default (sync->context);
236         _gsecret_sync_free (sync);
237
238         return ret;
239 }
240
241 typedef struct {
242         GCancellable *cancellable;
243         GHashTable *attributes;
244         GSecretValue *value;
245 } LookupClosure;
246
247 static void
248 lookup_closure_free (gpointer data)
249 {
250         LookupClosure *closure = data;
251         g_clear_object (&closure->cancellable);
252         g_hash_table_unref (closure->attributes);
253         if (closure->value)
254                 gsecret_value_unref (closure->value);
255         g_slice_free (LookupClosure, closure);
256 }
257
258 void
259 gsecret_password_lookup (const GSecretSchema *schema,
260                          GCancellable *cancellable,
261                          GAsyncReadyCallback callback,
262                          gpointer user_data,
263                          ...)
264 {
265         GHashTable *attributes;
266         va_list va;
267
268         g_return_if_fail (schema != NULL);
269         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
270
271         va_start (va, user_data);
272         attributes = _gsecret_util_attributes_for_varargs (schema, va);
273         va_end (va);
274
275         gsecret_password_lookupv (attributes, cancellable, callback, user_data);
276
277         g_hash_table_unref (attributes);
278 }
279
280 static void
281 on_lookup_complete (GObject *source,
282                     GAsyncResult *result,
283                     gpointer user_data)
284 {
285         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
286         LookupClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
287         GError *error = NULL;
288
289         closure->value = gsecret_service_lookup_finish (GSECRET_SERVICE (source),
290                                                         result, &error);
291
292         if (error != NULL)
293                 g_simple_async_result_take_error (res, error);
294
295         g_simple_async_result_complete (res);
296         g_object_unref (res);
297 }
298
299 static void
300 on_lookup_connected (GObject *source,
301                      GAsyncResult *result,
302                      gpointer user_data)
303 {
304         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
305         LookupClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
306         GSecretService *service;
307         GError *error = NULL;
308
309         service = gsecret_service_get_finish (result, &error);
310         if (error != NULL) {
311                 g_simple_async_result_take_error (res, error);
312                 g_simple_async_result_complete (res);
313
314         } else {
315                 gsecret_service_lookupv (service, closure->attributes, closure->cancellable,
316                                          on_lookup_complete, g_object_ref (res));
317                 g_object_unref (service);
318         }
319
320         g_object_unref (res);
321 }
322
323 void
324 gsecret_password_lookupv (GHashTable *attributes,
325                           GCancellable *cancellable,
326                           GAsyncReadyCallback callback,
327                           gpointer user_data)
328 {
329         GSimpleAsyncResult *res;
330         LookupClosure *closure;
331
332         g_return_if_fail (attributes != NULL);
333         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
334
335         res = g_simple_async_result_new (NULL, callback, user_data,
336                                          gsecret_password_lookupv);
337         closure = g_slice_new0 (LookupClosure);
338         closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
339         closure->attributes = g_hash_table_ref (attributes);
340         g_simple_async_result_set_op_res_gpointer (res, closure, lookup_closure_free);
341
342         gsecret_service_get (GSECRET_SERVICE_OPEN_SESSION, cancellable,
343                              on_lookup_connected, g_object_ref (res));
344
345         g_object_unref (res);
346 }
347
348 gchar *
349 gsecret_password_lookup_finish (GAsyncResult *result,
350                                 GError **error)
351 {
352         GSimpleAsyncResult *res;
353         LookupClosure *closure;
354         const gchar *content_type;
355         gchar *password = NULL;
356
357         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
358         g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
359                               gsecret_password_lookupv), NULL);
360
361         res = G_SIMPLE_ASYNC_RESULT (result);
362         if (g_simple_async_result_propagate_error (res, error))
363                 return NULL;
364
365         closure = g_simple_async_result_get_op_res_gpointer (res);
366         content_type = gsecret_value_get_content_type (closure->value);
367         if (content_type && g_str_equal (content_type, "text/plain")) {
368                 password = _gsecret_value_unref_to_password (closure->value);
369                 closure->value = NULL;
370         }
371
372         return password;
373 }
374
375 gchar *
376 gsecret_password_lookup_sync (const GSecretSchema *schema,
377                               GCancellable *cancellable,
378                               GError **error,
379                               ...)
380 {
381         GHashTable *attributes;
382         gchar *password;
383         va_list va;
384
385         g_return_val_if_fail (schema != NULL, NULL);
386         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
387         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
388
389         va_start (va, error);
390         attributes = _gsecret_util_attributes_for_varargs (schema, va);
391         va_end (va);
392
393         password = gsecret_password_lookupv_sync (attributes, cancellable, error);
394
395         g_hash_table_unref (attributes);
396
397         return password;
398 }
399
400 gchar *
401 gsecret_password_lookupv_sync (GHashTable *attributes,
402                                GCancellable *cancellable,
403                                GError **error)
404 {
405         GSecretSync *sync;
406         gchar *password;
407
408         g_return_val_if_fail (attributes != NULL, NULL);
409         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
410         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
411
412         sync = _gsecret_sync_new ();
413         g_main_context_push_thread_default (sync->context);
414
415         gsecret_password_lookupv (attributes, cancellable,
416                                   _gsecret_sync_on_result, sync);
417
418         g_main_loop_run (sync->loop);
419
420         password = gsecret_password_lookup_finish (sync->result, error);
421
422         g_main_context_pop_thread_default (sync->context);
423         _gsecret_sync_free (sync);
424
425         return password;
426 }
427
428 typedef struct {
429         GCancellable *cancellable;
430         GHashTable *attributes;
431         gboolean deleted;
432 } DeleteClosure;
433
434 static void
435 delete_closure_free (gpointer data)
436 {
437         DeleteClosure *closure = data;
438         g_clear_object (&closure->cancellable);
439         g_hash_table_unref (closure->attributes);
440         g_slice_free (DeleteClosure, closure);
441 }
442
443 void
444 gsecret_password_remove (const GSecretSchema *schema,
445                          GCancellable *cancellable,
446                          GAsyncReadyCallback callback,
447                          gpointer user_data,
448                          ...)
449 {
450         GHashTable *attributes;
451         va_list va;
452
453         g_return_if_fail (schema != NULL);
454         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
455
456         va_start (va, user_data);
457         attributes = _gsecret_util_attributes_for_varargs (schema, va);
458         va_end (va);
459
460         gsecret_password_removev (attributes, cancellable,
461                                   callback, user_data);
462
463         g_hash_table_unref (attributes);
464 }
465
466 static void
467 on_delete_complete (GObject *source,
468                     GAsyncResult *result,
469                     gpointer user_data)
470 {
471         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
472         DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
473         GError *error = NULL;
474
475         closure->deleted = gsecret_service_remove_finish (GSECRET_SERVICE (source),
476                                                           result, &error);
477         if (error != NULL)
478                 g_simple_async_result_take_error (res, error);
479         g_simple_async_result_complete (res);
480
481         g_object_unref (res);
482 }
483
484 static void
485 on_delete_connect (GObject *source,
486                    GAsyncResult *result,
487                    gpointer user_data)
488 {
489         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
490         DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
491         GSecretService *service;
492         GError *error = NULL;
493
494         service = gsecret_service_get_finish (result, &error);
495         if (error == NULL) {
496                 gsecret_service_removev (service, closure->attributes,
497                                          closure->cancellable, on_delete_complete,
498                                          g_object_ref (res));
499                 g_object_unref (service);
500
501         } else {
502                 g_simple_async_result_take_error (res, error);
503                 g_simple_async_result_complete (res);
504         }
505
506         g_object_unref (res);
507 }
508
509 void
510 gsecret_password_removev (GHashTable *attributes,
511                           GCancellable *cancellable,
512                           GAsyncReadyCallback callback,
513                           gpointer user_data)
514 {
515         GSimpleAsyncResult *res;
516         DeleteClosure *closure;
517
518         g_return_if_fail (attributes != NULL);
519         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
520
521         res = g_simple_async_result_new (NULL, callback, user_data,
522                                          gsecret_password_removev);
523         closure = g_slice_new0 (DeleteClosure);
524         closure->attributes = g_hash_table_ref (attributes);
525         closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
526         g_simple_async_result_set_op_res_gpointer (res, closure, delete_closure_free);
527
528         gsecret_service_get (GSECRET_SERVICE_NONE, cancellable,
529                              on_delete_connect, g_object_ref (res));
530
531         g_object_unref (res);
532 }
533
534 gboolean
535 gsecret_password_remove_finish (GAsyncResult *result,
536                                 GError **error)
537 {
538         DeleteClosure *closure;
539         GSimpleAsyncResult *res;
540
541         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
542         g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
543                               gsecret_password_removev), FALSE);
544
545         res = G_SIMPLE_ASYNC_RESULT (result);
546         if (g_simple_async_result_propagate_error (res, error))
547                 return FALSE;
548
549         closure = g_simple_async_result_get_op_res_gpointer (res);
550         return closure->deleted;
551 }
552
553 gboolean
554 gsecret_password_remove_sync (const GSecretSchema* schema,
555                               GCancellable *cancellable,
556                               GError **error,
557                               ...)
558 {
559         GHashTable *attributes;
560         gboolean result;
561         va_list va;
562
563         g_return_val_if_fail (schema != NULL, FALSE);
564         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
565         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
566
567         va_start (va, error);
568         attributes = _gsecret_util_attributes_for_varargs (schema, va);
569         va_end (va);
570
571         result = gsecret_password_removev_sync (attributes, cancellable, error);
572
573         g_hash_table_unref (attributes);
574
575         return result;
576 }
577
578 gboolean
579 gsecret_password_removev_sync (GHashTable *attributes,
580                                GCancellable *cancellable,
581                                GError **error)
582 {
583         GSecretSync *sync;
584         gboolean result;
585
586         g_return_val_if_fail (attributes != NULL, FALSE);
587         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
588         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
589
590         sync = _gsecret_sync_new ();
591         g_main_context_push_thread_default (sync->context);
592
593         gsecret_password_removev (attributes, cancellable,
594                                   _gsecret_sync_on_result, sync);
595
596         g_main_loop_run (sync->loop);
597
598         result = gsecret_password_remove_finish (sync->result, error);
599
600         g_main_context_pop_thread_default (sync->context);
601         _gsecret_sync_free (sync);
602
603         return result;
604 }
605
606 void
607 gsecret_password_free (gpointer password)
608 {
609         if (password == NULL)
610                 return;
611
612         egg_secure_strfree (password);
613 }