Branch data Line data Source code
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-private.h"
18 : : #include "secret-types.h"
19 : :
20 : : #include <string.h>
21 : :
22 : : /**
23 : : * SecretError:
24 : : * @SECRET_ERROR_PROTOCOL: received an invalid data or message from the Secret
25 : : * Service
26 : : * @SECRET_ERROR_IS_LOCKED: the item or collection is locked and the operation
27 : : * cannot be performed
28 : : * @SECRET_ERROR_NO_SUCH_OBJECT: no such item or collection found in the Secret
29 : : * Service
30 : : * @SECRET_ERROR_ALREADY_EXISTS: a relevant item or collection already exists
31 : : * @SECRET_ERROR_INVALID_FILE_FORMAT: the file format is not valid
32 : : * @SECRET_ERROR_MISMATCHED_SCHEMA: the xdg:schema attribute of the table does
33 : : * not match the schema name
34 : : * @SECRET_ERROR_NO_MATCHING_ATTRIBUTE: attribute contained in table not found
35 : : * in corresponding schema
36 : : * @SECRET_ERROR_WRONG_TYPE: attribute could not be parsed according to its type
37 : : * reported in the table's schema
38 : : * @SECRET_ERROR_EMPTY_TABLE: attribute list passed to secret_attributes_validate
39 : : * has no elements to validate
40 : : *
41 : : * Errors returned by the Secret Service.
42 : : *
43 : : * None of the errors are appropriate for display to the user. It is up to the
44 : : * application to handle them appropriately.
45 : : *
46 : : * Stability: Stable
47 : : */
48 : :
49 : : static void
50 : 1 : list_unref_free (GList *reflist)
51 : : {
52 : : GList *l;
53 [ + - + + ]: 4 : for (l = reflist; l; l = g_list_next (l)) {
54 [ - + ]: 3 : g_return_if_fail (G_IS_OBJECT (l->data));
55 : 3 : g_object_unref (l->data);
56 : : }
57 : 1 : g_list_free (reflist);
58 : : }
59 : :
60 : : static GList *
61 : 1 : list_ref_copy (GList *reflist)
62 : : {
63 : 1 : GList *l, *copy = g_list_copy (reflist);
64 [ + - + + ]: 4 : for (l = copy; l; l = g_list_next (l)) {
65 [ - + ]: 3 : g_return_val_if_fail (G_IS_OBJECT (l->data), NULL);
66 : 3 : g_object_ref (l->data);
67 : : }
68 : 1 : return copy;
69 : : }
70 : :
71 : : GType
72 : 18 : _secret_list_get_type (void)
73 : : {
74 : : static GType type = 0;
75 [ + + ]: 18 : if (!type)
76 : 12 : type = g_boxed_type_register_static ("SecretObjectList",
77 : : (GBoxedCopyFunc)list_ref_copy,
78 : : (GBoxedFreeFunc)list_unref_free);
79 : 18 : return type;
80 : :
81 : : }
82 : :
83 : : /**
84 : : * secret_error_get_quark:
85 : : *
86 : : * Get the error quark.
87 : : *
88 : : * Returns: the quark
89 : : */
90 : : GQuark
91 : 38 : secret_error_get_quark (void)
92 : : {
93 : : static gsize quark = 0;
94 : :
95 : : static const GDBusErrorEntry entries[] = {
96 : : { SECRET_ERROR_IS_LOCKED, "org.freedesktop.Secret.Error.IsLocked", },
97 : : { SECRET_ERROR_NO_SUCH_OBJECT, "org.freedesktop.Secret.Error.NoSuchObject", },
98 : : { SECRET_ERROR_ALREADY_EXISTS, "org.freedesktop.Secret.Error.AlreadyExists" },
99 : : };
100 : :
101 : 38 : g_dbus_error_register_error_domain ("secret-error", &quark,
102 : : entries, G_N_ELEMENTS (entries));
103 : :
104 : 38 : return quark;
105 : : }
106 : :
107 : : void
108 : 35 : _secret_util_strip_remote_error (GError **error)
109 : : {
110 : : gchar *remote;
111 : :
112 [ + - + + ]: 35 : if (error == NULL || *error == NULL)
113 : 30 : return;
114 : :
115 : 5 : remote = g_dbus_error_get_remote_error (*error);
116 [ + - ]: 5 : if (remote) {
117 [ + + ]: 5 : if (g_dbus_error_strip_remote_error (*error)) {
118 : 2 : g_info ("Remote error from secret service: %s: %s", remote, (*error)->message);
119 : : }
120 : 5 : g_free (remote);
121 : : }
122 : : }
123 : :
124 : : gchar *
125 : 17 : _secret_util_parent_path (const gchar *path)
126 : : {
127 : : const gchar *pos;
128 : :
129 [ - + ]: 17 : g_return_val_if_fail (path != NULL, NULL);
130 : :
131 : 17 : pos = strrchr (path, '/');
132 [ - + ]: 17 : g_return_val_if_fail (pos != NULL, NULL);
133 [ - + ]: 17 : g_return_val_if_fail (pos != path, NULL);
134 : :
135 : 17 : return g_strndup (path, pos - path);
136 : : }
137 : :
138 : : gboolean
139 : 52 : _secret_util_empty_path (const gchar *path)
140 : : {
141 [ - + ]: 52 : g_return_val_if_fail (path != NULL, TRUE);
142 [ + - + + ]: 52 : return (g_str_equal (path, "") || g_str_equal (path, "/"));
143 : : }
144 : :
145 : : gchar *
146 : 12 : _secret_util_collection_to_path (const gchar *collection)
147 : : {
148 [ + + ]: 12 : if (collection == NULL)
149 : 1 : collection = SECRET_COLLECTION_DEFAULT;
150 [ + + ]: 12 : if (strchr (collection, '/') == NULL)
151 : 3 : return g_strdup_printf ("/org/freedesktop/secrets/aliases/%s", collection);
152 : 9 : return g_strdup (collection);
153 : : }
154 : :
155 : : GVariant *
156 : 23 : _secret_util_variant_for_properties (GHashTable *properties)
157 : : {
158 : : GHashTableIter iter;
159 : : GVariantBuilder builder;
160 : : const gchar *name;
161 : : GVariant *value;
162 : :
163 [ - + ]: 23 : g_return_val_if_fail (properties != NULL, NULL);
164 : :
165 : 23 : g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
166 : :
167 : 23 : g_hash_table_iter_init (&iter, properties);
168 [ + + ]: 64 : while (g_hash_table_iter_next (&iter, (gpointer *)&name, (gpointer *)&value))
169 : 41 : g_variant_builder_add (&builder, "{sv}", name, value);
170 : :
171 : 23 : return g_variant_builder_end (&builder);
172 : : }
173 : :
174 : : static void
175 : 0 : process_get_all_reply (GDBusProxy *proxy,
176 : : GVariant *retval)
177 : : {
178 : 0 : const gchar *invalidated_properties[1] = { NULL };
179 : : GVariant *changed_properties;
180 : : GVariantIter *iter;
181 : : GVariant *value;
182 : : gchar *key;
183 : :
184 [ # # ]: 0 : if (!g_variant_is_of_type (retval, G_VARIANT_TYPE ("(a{sv})"))) {
185 : 0 : g_warning ("Value for GetAll reply with type `%s' does not match `(a{sv})'",
186 : : g_variant_get_type_string (retval));
187 : 0 : return;
188 : : }
189 : :
190 : 0 : g_variant_get (retval, "(a{sv})", &iter);
191 [ # # ]: 0 : while (g_variant_iter_loop (iter, "{sv}", &key, &value))
192 : 0 : g_dbus_proxy_set_cached_property (proxy, key, value);
193 : 0 : g_variant_iter_free (iter);
194 : :
195 : 0 : g_variant_get (retval, "(@a{sv})", &changed_properties);
196 : 0 : g_signal_emit_by_name (proxy, "g-properties-changed",
197 : : changed_properties, invalidated_properties);
198 : 0 : g_variant_unref (changed_properties);
199 : : }
200 : :
201 : : static void
202 : 0 : on_get_properties (GObject *source,
203 : : GAsyncResult *result,
204 : : gpointer user_data)
205 : : {
206 : 0 : GTask *task = G_TASK (user_data);
207 : 0 : GDBusProxy *proxy = G_DBUS_PROXY (g_task_get_source_object (task));
208 : 0 : GError *error = NULL;
209 : : GVariant *retval;
210 : :
211 : 0 : retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
212 : :
213 [ # # ]: 0 : if (error == NULL) {
214 : 0 : process_get_all_reply (proxy, retval);
215 : 0 : g_task_return_boolean (task, TRUE);
216 : : } else {
217 : 0 : g_task_return_error (task, g_steal_pointer (&error));
218 : : }
219 [ # # ]: 0 : if (retval != NULL)
220 : 0 : g_variant_unref (retval);
221 : :
222 [ # # ]: 0 : g_clear_object (&task);
223 : 0 : }
224 : :
225 : : void
226 : 0 : _secret_util_get_properties (GDBusProxy *proxy,
227 : : gpointer result_tag,
228 : : GCancellable *cancellable,
229 : : GAsyncReadyCallback callback,
230 : : gpointer user_data)
231 : : {
232 : : GTask *task;
233 : :
234 [ # # # # : 0 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
# # # # #
# ]
235 : :
236 : 0 : task = g_task_new (proxy, cancellable, callback, user_data);
237 [ # # ]: 0 : g_task_set_source_tag (task, result_tag);
238 : :
239 : 0 : g_dbus_connection_call (g_dbus_proxy_get_connection (proxy),
240 : : g_dbus_proxy_get_name (proxy),
241 : : g_dbus_proxy_get_object_path (proxy),
242 : : "org.freedesktop.DBus.Properties", "GetAll",
243 : : g_variant_new ("(s)", g_dbus_proxy_get_interface_name (proxy)),
244 : : G_VARIANT_TYPE ("(a{sv})"),
245 : : G_DBUS_CALL_FLAGS_NONE, -1,
246 : : cancellable, on_get_properties,
247 : : g_steal_pointer (&task));
248 : :
249 [ # # ]: 0 : g_clear_object (&task);
250 : : }
251 : :
252 : : gboolean
253 : 0 : _secret_util_get_properties_finish (GDBusProxy *proxy,
254 : : gpointer result_tag,
255 : : GAsyncResult *result,
256 : : GError **error)
257 : : {
258 [ # # ]: 0 : g_return_val_if_fail (g_task_is_valid (result, proxy), FALSE);
259 [ # # ]: 0 : g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == result_tag, FALSE);
260 [ # # # # ]: 0 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
261 : :
262 [ # # ]: 0 : if (!g_task_propagate_boolean (G_TASK (result), error)) {
263 : 0 : _secret_util_strip_remote_error (error);
264 : 0 : return FALSE;
265 : : }
266 : :
267 : 0 : return TRUE;
268 : : }
269 : :
270 : : typedef struct {
271 : : gchar *property;
272 : : GVariant *value;
273 : : gboolean result;
274 : : } SetClosure;
275 : :
276 : : static void
277 : 6 : set_closure_free (gpointer data)
278 : : {
279 : 6 : SetClosure *closure = data;
280 : 6 : g_free (closure->property);
281 : 6 : g_variant_unref (closure->value);
282 : 6 : g_free (closure);
283 : 6 : }
284 : :
285 : : static void
286 : 6 : on_set_property (GObject *source,
287 : : GAsyncResult *result,
288 : : gpointer user_data)
289 : : {
290 : 6 : GTask *task = G_TASK (user_data);
291 : 6 : SetClosure *closure = g_task_get_task_data (task);
292 : 6 : GDBusProxy *proxy = G_DBUS_PROXY (g_task_get_source_object (user_data));
293 : 6 : GError *error = NULL;
294 : : GVariant *retval;
295 : 6 : gboolean success = FALSE;
296 : :
297 : 6 : retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source),
298 : : result, &error);
299 [ - + ]: 6 : if (error != NULL) {
300 : 0 : g_task_return_error (task, g_steal_pointer (&error));
301 : : } else {
302 : 6 : success = (retval != NULL);
303 : :
304 [ + - ]: 6 : if (success) {
305 : 6 : g_dbus_proxy_set_cached_property (proxy, closure->property, closure->value);
306 : 6 : g_variant_unref (retval);
307 : : }
308 : :
309 : 6 : g_task_return_boolean (task, success);
310 : : }
311 : :
312 [ + - ]: 6 : g_clear_object (&task);
313 : 6 : }
314 : :
315 : : void
316 : 6 : _secret_util_set_property (GDBusProxy *proxy,
317 : : const gchar *property,
318 : : GVariant *value,
319 : : gpointer result_tag,
320 : : GCancellable *cancellable,
321 : : GAsyncReadyCallback callback,
322 : : gpointer user_data)
323 : : {
324 : : GTask *task;
325 : : SetClosure *closure;
326 : :
327 [ + + - + : 6 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+ - + - -
+ ]
328 : :
329 : 6 : task = g_task_new (proxy, cancellable, callback, user_data);
330 [ + - ]: 6 : g_task_set_source_tag (task, result_tag);
331 : 6 : closure = g_new0 (SetClosure, 1);
332 : 6 : closure->property = g_strdup (property);
333 : 6 : closure->value = g_variant_ref_sink (value);
334 : 6 : g_task_set_task_data (task, closure, set_closure_free);
335 : :
336 : 6 : g_dbus_connection_call (g_dbus_proxy_get_connection (proxy),
337 : : g_dbus_proxy_get_name (proxy),
338 : : g_dbus_proxy_get_object_path (proxy),
339 : : SECRET_PROPERTIES_INTERFACE,
340 : : "Set",
341 : : g_variant_new ("(ssv)",
342 : : g_dbus_proxy_get_interface_name (proxy),
343 : : property,
344 : : closure->value),
345 : : G_VARIANT_TYPE ("()"),
346 : : G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
347 : : cancellable, on_set_property,
348 : : g_steal_pointer (&task));
349 : :
350 [ - + ]: 6 : g_clear_object (&task);
351 : : }
352 : :
353 : : gboolean
354 : 6 : _secret_util_set_property_finish (GDBusProxy *proxy,
355 : : gpointer result_tag,
356 : : GAsyncResult *result,
357 : : GError **error)
358 : : {
359 [ - + ]: 6 : g_return_val_if_fail (g_task_is_valid (result, proxy), FALSE);
360 [ - + ]: 6 : g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == result_tag, FALSE);
361 [ + - - + ]: 6 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
362 : :
363 [ - + ]: 6 : if (!g_task_propagate_boolean (G_TASK (result), error)) {
364 : 0 : _secret_util_strip_remote_error (error);
365 : 0 : return FALSE;
366 : : }
367 : :
368 : 6 : return TRUE;
369 : : }
370 : :
371 : : gboolean
372 : 3 : _secret_util_set_property_sync (GDBusProxy *proxy,
373 : : const gchar *property,
374 : : GVariant *value,
375 : : GCancellable *cancellable,
376 : : GError **error)
377 : : {
378 : 3 : gboolean result = FALSE;
379 : : GVariant *retval;
380 : :
381 [ - + - - : 3 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
- - - - -
- ]
382 [ + - - + ]: 3 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
383 : :
384 : 3 : g_variant_ref_sink (value);
385 : :
386 : 3 : retval = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (proxy),
387 : : g_dbus_proxy_get_name (proxy),
388 : : g_dbus_proxy_get_object_path (proxy),
389 : : SECRET_PROPERTIES_INTERFACE,
390 : : "Set",
391 : : g_variant_new ("(ssv)",
392 : : g_dbus_proxy_get_interface_name (proxy),
393 : : property,
394 : : value),
395 : : G_VARIANT_TYPE ("()"),
396 : : G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
397 : : cancellable, error);
398 : :
399 [ + - ]: 3 : if (retval != NULL) {
400 : 3 : result = TRUE;
401 : 3 : g_variant_unref (retval);
402 : 3 : g_dbus_proxy_set_cached_property (proxy, property, value);
403 : : }
404 : :
405 : 3 : g_variant_unref (value);
406 : :
407 : 3 : return result;
408 : : }
409 : :
410 : : gboolean
411 : 219 : _secret_util_have_cached_properties (GDBusProxy *proxy)
412 : : {
413 : : gchar **names;
414 : :
415 : 219 : names = g_dbus_proxy_get_cached_property_names (proxy);
416 : 219 : g_strfreev (names);
417 : :
418 : 219 : return names != NULL;
419 : : }
420 : :
421 : : SecretSync *
422 : 110 : _secret_sync_new (void)
423 : : {
424 : : SecretSync *sync;
425 : :
426 : 110 : sync = g_new0 (SecretSync, 1);
427 : :
428 : 110 : sync->context = g_main_context_new ();
429 : 110 : sync->loop = g_main_loop_new (sync->context, FALSE);
430 : :
431 : 110 : return sync;
432 : : }
433 : :
434 : : void
435 : 110 : _secret_sync_free (gpointer data)
436 : : {
437 : 110 : SecretSync *sync = data;
438 : :
439 [ + + ]: 114 : while (g_main_context_iteration (sync->context, FALSE));
440 : :
441 [ + - ]: 110 : g_clear_object (&sync->result);
442 : 110 : g_main_loop_unref (sync->loop);
443 : 110 : g_main_context_unref (sync->context);
444 : 110 : g_free (sync);
445 : 110 : }
446 : :
447 : : void
448 : 110 : _secret_sync_on_result (GObject *source,
449 : : GAsyncResult *result,
450 : : gpointer user_data)
451 : : {
452 : 110 : SecretSync *sync = user_data;
453 [ - + ]: 110 : g_assert (sync->result == NULL);
454 : 110 : sync->result = g_object_ref (result);
455 : 110 : g_main_loop_quit (sync->loop);
456 : 110 : }
|