Line data Source code
1 : /*
2 : * gnome-keyring
3 : *
4 : * Copyright (C) 2008 Stefan Walter
5 : *
6 : * This program is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU Lesser General Public License as
8 : * published by the Free Software Foundation; either version 2.1 of
9 : * the License, or (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful, but
12 : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * Lesser General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public
17 : * License along with this program; if not, see
18 : * <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "config.h"
22 :
23 : #include "gkd-secret-error.h"
24 : #include "gkd-secret-objects.h"
25 : #include "gkd-secret-property.h"
26 : #include "gkd-secret-secret.h"
27 : #include "gkd-secret-service.h"
28 : #include "gkd-secret-session.h"
29 : #include "gkd-secret-types.h"
30 : #include "gkd-secret-util.h"
31 : #include "gkd-secrets-generated.h"
32 :
33 : #include "egg/egg-error.h"
34 :
35 : #include "pkcs11/pkcs11i.h"
36 :
37 : #include <string.h>
38 :
39 : struct _GkdSecretObjects {
40 : GObject parent;
41 : GkdSecretService *service;
42 : GckSlot *pkcs11_slot;
43 : GHashTable *collections_to_skeletons;
44 : GHashTable *items_to_skeletons;
45 : };
46 :
47 :
48 : /* -----------------------------------------------------------------------------
49 : * SKELETON
50 : */
51 :
52 : typedef struct {
53 : GkdExportedCollectionSkeleton parent;
54 : GkdSecretObjects *objects;
55 : } GkdSecretCollectionSkeleton;
56 : typedef struct {
57 : GkdExportedCollectionSkeletonClass parent_class;
58 : } GkdSecretCollectionSkeletonClass;
59 : typedef struct {
60 : GkdExportedItemSkeleton parent;
61 : GkdSecretObjects *objects;
62 : } GkdSecretItemSkeleton;
63 : typedef struct {
64 : GkdExportedItemSkeletonClass parent_class;
65 : } GkdSecretItemSkeletonClass;
66 :
67 : static GckObject * secret_objects_lookup_gck_object_for_path (GkdSecretObjects *self,
68 : const gchar *sender,
69 : const gchar *path,
70 : GError **error);
71 :
72 : GType gkd_secret_collection_skeleton_get_type (void);
73 100 : G_DEFINE_TYPE (GkdSecretCollectionSkeleton, gkd_secret_collection_skeleton, GKD_TYPE_EXPORTED_COLLECTION_SKELETON)
74 : GType gkd_secret_item_skeleton_get_type (void);
75 71 : G_DEFINE_TYPE (GkdSecretItemSkeleton, gkd_secret_item_skeleton, GKD_TYPE_EXPORTED_ITEM_SKELETON)
76 :
77 : static void
78 84 : on_object_path_append_to_builder (GkdSecretObjects *self,
79 : const gchar *path,
80 : GckObject *object,
81 : gpointer user_data)
82 : {
83 84 : GVariantBuilder *builder = user_data;
84 84 : g_variant_builder_add (builder, "o", path);
85 84 : }
86 :
87 : static GVariant *
88 53 : gkd_secret_objects_append_item_paths (GkdSecretObjects *self,
89 : const gchar *caller,
90 : const gchar *base)
91 : {
92 : GVariantBuilder builder;
93 :
94 53 : g_return_val_if_fail (GKD_SECRET_IS_OBJECTS (self), NULL);
95 53 : g_return_val_if_fail (base, NULL);
96 :
97 53 : g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
98 53 : gkd_secret_objects_foreach_item (self, caller, base, on_object_path_append_to_builder, &builder);
99 :
100 53 : return g_variant_builder_end (&builder);
101 : }
102 :
103 : static gchar **
104 53 : gkd_secret_objects_get_collection_items (GkdSecretObjects *self,
105 : const gchar *collection_path)
106 : {
107 : GVariant *items_variant;
108 : gchar **items;
109 :
110 53 : items_variant = gkd_secret_objects_append_item_paths (self, NULL, collection_path);
111 53 : items = g_variant_dup_objv (items_variant, NULL);
112 53 : g_variant_unref (items_variant);
113 :
114 53 : return items;
115 : }
116 :
117 : static gboolean
118 2 : object_property_set (GkdSecretObjects *objects,
119 : GckObject *object,
120 : const gchar *prop_name,
121 : GVariant *value,
122 : GError **error_out)
123 : {
124 2 : GckBuilder builder = GCK_BUILDER_INIT;
125 2 : GError *error = NULL;
126 : gulong attr_type;
127 :
128 : /* What type of property is it? */
129 2 : if (!gkd_secret_property_get_type (prop_name, &attr_type)) {
130 0 : g_set_error (error_out, G_DBUS_ERROR,
131 : G_DBUS_ERROR_UNKNOWN_PROPERTY,
132 : "Object does not have the '%s' property",
133 : prop_name);
134 0 : return FALSE;
135 : }
136 :
137 : /* Retrieve the actual attribute value */
138 2 : if (!gkd_secret_property_parse_variant (value, prop_name, &builder)) {
139 0 : gck_builder_clear (&builder);
140 0 : g_set_error (error_out, G_DBUS_ERROR,
141 : G_DBUS_ERROR_INVALID_ARGS,
142 : "The property type or value was invalid: %s",
143 : prop_name);
144 0 : return FALSE;
145 : }
146 :
147 2 : gck_object_set (object, gck_builder_end (&builder), NULL, &error);
148 :
149 2 : if (error != NULL) {
150 0 : if (g_error_matches (error, GCK_ERROR, CKR_USER_NOT_LOGGED_IN))
151 0 : g_set_error (error_out, GKD_SECRET_ERROR,
152 : GKD_SECRET_ERROR_IS_LOCKED,
153 : "Cannot set property on a locked object");
154 : else
155 0 : g_set_error (error_out, G_DBUS_ERROR,
156 : G_DBUS_ERROR_FAILED,
157 : "Couldn't set '%s' property: %s",
158 : prop_name, egg_error_message (error));
159 0 : g_clear_error (&error);
160 0 : return FALSE;
161 : }
162 :
163 2 : return TRUE;
164 : }
165 :
166 : static GVariant *
167 49 : object_property_get (GkdSecretObjects *objects,
168 : GckObject *object,
169 : const gchar *prop_name,
170 : GError **error_out)
171 : {
172 49 : GError *error = NULL;
173 : GckAttribute attr;
174 : gpointer value;
175 : gsize length;
176 : GVariant *res;
177 :
178 49 : if (!gkd_secret_property_get_type (prop_name, &attr.type)) {
179 0 : g_set_error (error_out, G_DBUS_ERROR,
180 : G_DBUS_ERROR_UNKNOWN_PROPERTY,
181 : "Object does not have the '%s' property",
182 : prop_name);
183 0 : return NULL;
184 : }
185 :
186 : /* Retrieve the actual attribute */
187 49 : attr.value = value = gck_object_get_data (object, attr.type, NULL, &length, &error);
188 49 : if (error != NULL) {
189 0 : g_set_error (error_out, G_DBUS_ERROR,
190 : G_DBUS_ERROR_FAILED,
191 : "Couldn't retrieve '%s' property: %s",
192 : prop_name, egg_error_message (error));
193 0 : g_clear_error (&error);
194 0 : return NULL;
195 : }
196 :
197 : /* Marshall the data back out */
198 49 : attr.length = length;
199 49 : res = gkd_secret_property_append_variant (&attr);
200 49 : g_free (value);
201 :
202 49 : return res;
203 : }
204 :
205 : static gboolean
206 1 : gkd_secret_collection_skeleton_set_property_dbus (GDBusConnection *connection,
207 : const gchar *sender,
208 : const gchar *object_path,
209 : const gchar *interface_name,
210 : const gchar *property_name,
211 : GVariant *value,
212 : GError **error,
213 : gpointer user_data)
214 : {
215 1 : GkdSecretCollectionSkeleton *self = (GkdSecretCollectionSkeleton *) user_data;
216 : GckObject *object;
217 :
218 1 : object = secret_objects_lookup_gck_object_for_path (self->objects, sender, object_path, error);
219 1 : if (!object)
220 0 : return FALSE;
221 :
222 1 : if (!object_property_set (self->objects, object, property_name, value, error)) {
223 0 : g_object_unref (object);
224 0 : return FALSE;
225 : }
226 :
227 1 : if (g_strcmp0 (property_name, "Label") == 0) {
228 1 : gkd_exported_collection_set_label (GKD_EXPORTED_COLLECTION (self),
229 : g_variant_get_string (value, NULL));
230 : }
231 :
232 1 : gkd_secret_service_emit_collection_changed (self->objects->service, object_path);
233 1 : g_object_unref (object);
234 :
235 1 : return TRUE;
236 : }
237 :
238 : static GVariant *
239 3 : gkd_secret_collection_skeleton_get_property_dbus (GDBusConnection *connection,
240 : const gchar *sender,
241 : const gchar *object_path,
242 : const gchar *interface_name,
243 : const gchar *property_name,
244 : GError **error,
245 : gpointer user_data)
246 : {
247 3 : GkdSecretCollectionSkeleton *self = (GkdSecretCollectionSkeleton *) user_data;
248 : GckObject *object;
249 : GVariant *variant;
250 :
251 3 : object = secret_objects_lookup_gck_object_for_path (self->objects, sender, object_path, error);
252 3 : if (!object)
253 0 : return FALSE;
254 :
255 3 : if (g_strcmp0 (property_name, "Items") == 0)
256 0 : variant = gkd_secret_objects_append_item_paths (self->objects, sender, object_path);
257 : else
258 3 : variant = object_property_get (self->objects, object, property_name, error);
259 :
260 :
261 3 : g_object_unref (object);
262 3 : return variant;
263 : }
264 :
265 : static GDBusInterfaceVTable *
266 54 : gkd_secret_collection_skeleton_get_vtable (GDBusInterfaceSkeleton *skeleton)
267 : {
268 : static GDBusInterfaceVTable vtable;
269 : GDBusInterfaceVTable *parent_vtable;
270 :
271 54 : parent_vtable = G_DBUS_INTERFACE_SKELETON_CLASS (gkd_secret_collection_skeleton_parent_class)->get_vtable (skeleton);
272 :
273 54 : (&vtable)->get_property = gkd_secret_collection_skeleton_get_property_dbus;
274 54 : (&vtable)->set_property = gkd_secret_collection_skeleton_set_property_dbus;
275 54 : (&vtable)->method_call = parent_vtable->method_call;
276 :
277 54 : return &vtable;
278 : }
279 :
280 : static void
281 25 : gkd_secret_collection_skeleton_class_init (GkdSecretCollectionSkeletonClass *klass)
282 : {
283 25 : GDBusInterfaceSkeletonClass *skclass = G_DBUS_INTERFACE_SKELETON_CLASS (klass);
284 25 : skclass->get_vtable = gkd_secret_collection_skeleton_get_vtable;
285 25 : }
286 :
287 : static void
288 50 : gkd_secret_collection_skeleton_init (GkdSecretCollectionSkeleton *self)
289 : {
290 50 : }
291 :
292 : static GkdExportedCollection *
293 50 : gkd_secret_collection_skeleton_new (GkdSecretObjects *objects)
294 : {
295 50 : GkdExportedCollection *self = g_object_new (gkd_secret_collection_skeleton_get_type (), NULL);
296 50 : ((GkdSecretCollectionSkeleton *) self)->objects = objects;
297 50 : return self;
298 : }
299 :
300 : static gboolean
301 1 : gkd_secret_item_skeleton_set_property_dbus (GDBusConnection *connection,
302 : const gchar *sender,
303 : const gchar *object_path,
304 : const gchar *interface_name,
305 : const gchar *property_name,
306 : GVariant *value,
307 : GError **error,
308 : gpointer user_data)
309 : {
310 1 : GkdSecretItemSkeleton *self = (GkdSecretItemSkeleton *) user_data;
311 : GckObject *object;
312 :
313 1 : object = secret_objects_lookup_gck_object_for_path (self->objects, sender, object_path, error);
314 1 : if (!object)
315 0 : return FALSE;
316 :
317 1 : if (!object_property_set (self->objects, object, property_name, value, error)) {
318 0 : g_object_unref (object);
319 0 : return FALSE;
320 : }
321 :
322 1 : if (g_strcmp0 (property_name, "Attributes") == 0) {
323 0 : gkd_exported_item_set_attributes (GKD_EXPORTED_ITEM (self), value);
324 1 : } else if (g_strcmp0 (property_name, "Label") == 0) {
325 1 : gkd_exported_item_set_label (GKD_EXPORTED_ITEM (self),
326 : g_variant_get_string (value, NULL));
327 : }
328 :
329 1 : gkd_secret_objects_emit_item_changed (self->objects, object);
330 1 : g_object_unref (object);
331 :
332 1 : return TRUE;
333 : }
334 :
335 : static GVariant *
336 6 : gkd_secret_item_skeleton_get_property_dbus (GDBusConnection *connection,
337 : const gchar *sender,
338 : const gchar *object_path,
339 : const gchar *interface_name,
340 : const gchar *property_name,
341 : GError **error,
342 : gpointer user_data)
343 : {
344 6 : GkdSecretItemSkeleton *self = (GkdSecretItemSkeleton *) user_data;
345 : GckObject *object;
346 : GVariant *variant;
347 :
348 6 : object = secret_objects_lookup_gck_object_for_path (self->objects, sender, object_path, error);
349 6 : if (!object)
350 0 : return NULL;
351 :
352 6 : variant = object_property_get (self->objects, object, property_name, error);
353 6 : g_object_unref (object);
354 :
355 6 : return variant;
356 : }
357 :
358 : static GDBusInterfaceVTable *
359 26 : gkd_secret_item_skeleton_get_vtable (GDBusInterfaceSkeleton *skeleton)
360 : {
361 : static GDBusInterfaceVTable vtable;
362 : GDBusInterfaceVTable *parent_vtable;
363 :
364 26 : parent_vtable = G_DBUS_INTERFACE_SKELETON_CLASS (gkd_secret_item_skeleton_parent_class)->get_vtable (skeleton);
365 :
366 26 : (&vtable)->get_property = gkd_secret_item_skeleton_get_property_dbus;
367 26 : (&vtable)->set_property = gkd_secret_item_skeleton_set_property_dbus;
368 26 : (&vtable)->method_call = parent_vtable->method_call;
369 :
370 26 : return &vtable;
371 : }
372 :
373 : static void
374 23 : gkd_secret_item_skeleton_class_init (GkdSecretItemSkeletonClass *klass)
375 : {
376 23 : GDBusInterfaceSkeletonClass *skclass = G_DBUS_INTERFACE_SKELETON_CLASS (klass);
377 23 : skclass->get_vtable = gkd_secret_item_skeleton_get_vtable;
378 23 : }
379 :
380 : static void
381 25 : gkd_secret_item_skeleton_init (GkdSecretItemSkeleton *self)
382 : {
383 25 : }
384 :
385 : static GkdExportedItem *
386 25 : gkd_secret_item_skeleton_new (GkdSecretObjects *objects)
387 : {
388 25 : GkdExportedItem *self = g_object_new (gkd_secret_item_skeleton_get_type (), NULL);
389 25 : ((GkdSecretItemSkeleton *) self)->objects = objects;
390 25 : return self;
391 : }
392 :
393 : enum {
394 : PROP_0,
395 : PROP_PKCS11_SLOT,
396 : PROP_SERVICE
397 : };
398 :
399 : static gchar * object_path_for_item (const gchar *base,
400 : GckObject *item);
401 :
402 : static gchar * object_path_for_collection (GckObject *collection);
403 :
404 : static gchar * collection_path_for_item (GckObject *item);
405 :
406 445 : G_DEFINE_TYPE (GkdSecretObjects, gkd_secret_objects, G_TYPE_OBJECT);
407 :
408 : /* -----------------------------------------------------------------------------
409 : * INTERNAL
410 : */
411 :
412 : static GckObject *
413 15 : secret_objects_lookup_gck_object_for_path (GkdSecretObjects *self,
414 : const gchar *sender,
415 : const gchar *path,
416 : GError **error_out)
417 : {
418 15 : GckBuilder builder = GCK_BUILDER_INIT;
419 : GList *objects;
420 : GckSession *session;
421 : gchar *c_ident;
422 : gchar *i_ident;
423 15 : GckObject *object = NULL;
424 15 : GError *error = NULL;
425 :
426 15 : g_return_val_if_fail (path, FALSE);
427 :
428 15 : if (!gkd_secret_util_parse_path (path, &c_ident, &i_ident) || !c_ident)
429 0 : goto out;
430 :
431 : /* The session we're using to access the object */
432 15 : session = gkd_secret_service_get_pkcs11_session (self->service, sender);
433 15 : g_return_val_if_fail (session, FALSE);
434 :
435 15 : if (i_ident) {
436 8 : gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
437 8 : gck_builder_add_string (&builder, CKA_G_COLLECTION, c_ident);
438 8 : gck_builder_add_string (&builder, CKA_ID, i_ident);
439 : } else {
440 7 : gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_COLLECTION);
441 7 : gck_builder_add_string (&builder, CKA_ID, c_ident);
442 : }
443 :
444 15 : objects = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);
445 :
446 15 : g_free (c_ident);
447 15 : g_free (i_ident);
448 :
449 15 : if (error != NULL) {
450 0 : g_warning ("couldn't lookup object: %s: %s", path, egg_error_message (error));
451 0 : g_clear_error (&error);
452 : }
453 :
454 15 : if (!objects)
455 0 : goto out;
456 :
457 15 : object = g_object_ref (objects->data);
458 15 : gck_list_unref_free (objects);
459 :
460 15 : out:
461 15 : if (!object)
462 0 : g_set_error (error_out, GKD_SECRET_ERROR,
463 : GKD_SECRET_ERROR_NO_SUCH_OBJECT,
464 : "The '%s' object does not exist",
465 : path);
466 :
467 15 : return object;
468 : }
469 :
470 : static GckObject *
471 4 : secret_objects_lookup_gck_object_for_invocation (GkdSecretObjects *self,
472 : GDBusMethodInvocation *invocation)
473 : {
474 4 : GError *error = NULL;
475 : GckObject *object;
476 :
477 4 : object = secret_objects_lookup_gck_object_for_path (self,
478 : g_dbus_method_invocation_get_sender (invocation),
479 : g_dbus_method_invocation_get_object_path (invocation),
480 : &error);
481 :
482 4 : if (!object)
483 0 : g_dbus_method_invocation_take_error (invocation, error);
484 :
485 4 : return object;
486 : }
487 :
488 : static gboolean
489 1 : item_method_delete (GkdExportedItem *skeleton,
490 : GDBusMethodInvocation *invocation,
491 : GkdSecretObjects *self)
492 : {
493 1 : GError *error = NULL;
494 : gchar *collection_path;
495 : gchar *item_path;
496 : GckObject *collection;
497 : GckObject *object;
498 :
499 1 : object = secret_objects_lookup_gck_object_for_invocation (self, invocation);
500 1 : if (!object) {
501 0 : return TRUE;
502 : }
503 :
504 1 : collection_path = collection_path_for_item (object);
505 1 : item_path = object_path_for_item (NULL, object);
506 :
507 1 : if (gck_object_destroy (object, NULL, &error)) {
508 1 : collection = gkd_secret_objects_lookup_collection (self, NULL, collection_path);
509 1 : if (collection != NULL) {
510 1 : gkd_secret_objects_emit_item_deleted (self, collection, item_path);
511 1 : g_object_unref (collection);
512 : }
513 :
514 : /* No prompt necessary */
515 1 : gkd_exported_item_complete_delete (skeleton, invocation, "/");
516 :
517 : } else {
518 0 : if (g_error_matches (error, GCK_ERROR, CKR_USER_NOT_LOGGED_IN))
519 0 : g_dbus_method_invocation_return_error_literal (invocation, GKD_SECRET_ERROR,
520 : GKD_SECRET_ERROR_IS_LOCKED,
521 : "Cannot delete a locked item");
522 : else
523 0 : g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
524 : G_DBUS_ERROR_FAILED,
525 : "Couldn't delete collection: %s",
526 : egg_error_message (error));
527 :
528 0 : g_clear_error (&error);
529 : }
530 :
531 1 : g_free (collection_path);
532 1 : g_free (item_path);
533 1 : g_object_unref (object);
534 :
535 1 : return TRUE;
536 : }
537 :
538 : static gboolean
539 0 : item_method_get_secret (GkdExportedItem *skeleton,
540 : GDBusMethodInvocation *invocation,
541 : gchar *path,
542 : GkdSecretObjects *self)
543 : {
544 : GkdSecretSession *session;
545 : GkdSecretSecret *secret;
546 : GckObject *item;
547 0 : GError *error = NULL;
548 :
549 0 : item = secret_objects_lookup_gck_object_for_invocation (self, invocation);
550 0 : if (!item) {
551 0 : return TRUE;
552 : }
553 :
554 0 : session = gkd_secret_service_lookup_session (self->service, path,
555 : g_dbus_method_invocation_get_sender (invocation));
556 0 : if (session == NULL) {
557 0 : g_dbus_method_invocation_return_error_literal (invocation, GKD_SECRET_ERROR,
558 : GKD_SECRET_ERROR_NO_SESSION,
559 : "The session does not exist");
560 0 : goto cleanup;
561 : }
562 :
563 0 : secret = gkd_secret_session_get_item_secret (session, item, &error);
564 0 : if (secret == NULL) {
565 0 : g_dbus_method_invocation_take_error (invocation, error);
566 0 : goto cleanup;
567 : }
568 :
569 0 : gkd_exported_item_complete_get_secret (skeleton, invocation,
570 : gkd_secret_secret_append (secret));
571 0 : gkd_secret_secret_free (secret);
572 :
573 0 : cleanup:
574 0 : g_object_unref (item);
575 0 : return TRUE;
576 : }
577 :
578 : static gboolean
579 0 : item_method_set_secret (GkdExportedItem *skeleton,
580 : GDBusMethodInvocation *invocation,
581 : GVariant *secret_variant,
582 : GkdSecretObjects *self)
583 : {
584 : GkdSecretSecret *secret;
585 : const char *caller;
586 : GckObject *item;
587 0 : GError *error = NULL;
588 :
589 0 : item = secret_objects_lookup_gck_object_for_invocation (self, invocation);
590 0 : if (!item) {
591 0 : return TRUE;
592 : }
593 :
594 0 : caller = g_dbus_method_invocation_get_sender (invocation);
595 0 : secret = gkd_secret_secret_parse (self->service, caller, secret_variant, &error);
596 0 : if (error != NULL) {
597 0 : goto cleanup;
598 : }
599 :
600 0 : gkd_secret_session_set_item_secret (secret->session, item, secret, &error);
601 0 : gkd_secret_secret_free (secret);
602 :
603 0 : if (error != NULL) {
604 0 : goto cleanup;
605 : }
606 :
607 0 : cleanup:
608 0 : if (error != NULL) {
609 0 : g_dbus_method_invocation_take_error (invocation, error);
610 : } else {
611 0 : gkd_exported_item_complete_set_secret (skeleton, invocation);
612 : }
613 :
614 0 : g_object_unref (item);
615 0 : return TRUE;
616 : }
617 :
618 : static void
619 1 : item_cleanup_search_results (GckSession *session, GList *items,
620 : GList **locked, GList **unlocked)
621 : {
622 1 : GError *error = NULL;
623 : gpointer value;
624 : gsize n_value;
625 : GList *l;
626 :
627 1 : *locked = NULL;
628 1 : *unlocked = NULL;
629 :
630 2 : for (l = items; l; l = g_list_next (l)) {
631 1 : value = gck_object_get_data (l->data, CKA_G_LOCKED, NULL, &n_value, &error);
632 1 : if (value == NULL) {
633 0 : if (!g_error_matches (error, GCK_ERROR, CKR_OBJECT_HANDLE_INVALID))
634 0 : g_warning ("couldn't check if item is locked: %s", egg_error_message (error));
635 0 : g_clear_error (&error);
636 :
637 : /* Is not locked */
638 1 : } if (n_value == 1 && *((CK_BBOOL*)value) == CK_FALSE) {
639 0 : *unlocked = g_list_prepend (*unlocked, l->data);
640 :
641 : /* Is locked */
642 : } else {
643 1 : *locked = g_list_prepend (*locked, l->data);
644 : }
645 :
646 1 : g_free (value);
647 : }
648 :
649 1 : *locked = g_list_reverse (*locked);
650 1 : *unlocked = g_list_reverse (*unlocked);
651 1 : }
652 :
653 : static gboolean
654 1 : collection_method_search_items (GkdExportedCollection *skeleton,
655 : GDBusMethodInvocation *invocation,
656 : GVariant *attributes,
657 : GkdSecretObjects *self)
658 : {
659 1 : return gkd_secret_objects_handle_search_items (self, invocation, attributes,
660 : g_dbus_method_invocation_get_object_path (invocation),
661 : FALSE);
662 : }
663 :
664 : static GckObject*
665 0 : collection_find_matching_item (GkdSecretObjects *self,
666 : GckSession *session,
667 : const gchar *identifier,
668 : const GckAttribute *fields)
669 : {
670 0 : GckBuilder builder = GCK_BUILDER_INIT;
671 0 : GckObject *result = NULL;
672 0 : GError *error = NULL;
673 : GckObject *search;
674 : gpointer data;
675 : gsize n_data;
676 :
677 : /* Find items matching the collection and fields */
678 0 : gck_builder_add_attribute (&builder, fields);
679 0 : gck_builder_add_string (&builder, CKA_G_COLLECTION, identifier);
680 0 : gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_SEARCH);
681 0 : gck_builder_add_boolean (&builder, CKA_TOKEN, FALSE);
682 :
683 : /* Create the search object */
684 0 : search = gck_session_create_object (session, gck_builder_end (&builder), NULL, &error);
685 :
686 0 : if (error != NULL) {
687 0 : g_warning ("couldn't search for matching item: %s", egg_error_message (error));
688 0 : g_clear_error (&error);
689 0 : return NULL;
690 : }
691 :
692 : /* Get the matched item handles, and delete the search object */
693 0 : data = gck_object_get_data (search, CKA_G_MATCHED, NULL, &n_data, NULL);
694 0 : gck_object_destroy (search, NULL, NULL);
695 0 : g_object_unref (search);
696 :
697 0 : if (n_data >= sizeof (CK_OBJECT_HANDLE))
698 0 : result = gck_object_from_handle (session, *((CK_OBJECT_HANDLE_PTR)data));
699 :
700 0 : g_free (data);
701 0 : return result;
702 : }
703 :
704 : static gchar *
705 73 : object_path_for_item (const gchar *base,
706 : GckObject *item)
707 : {
708 73 : GError *error = NULL;
709 : gpointer identifier;
710 : gsize n_identifier;
711 73 : gchar *alloc = NULL;
712 73 : gchar *path = NULL;
713 :
714 73 : if (base == NULL)
715 3 : base = alloc = collection_path_for_item (item);
716 :
717 73 : identifier = gck_object_get_data (item, CKA_ID, NULL, &n_identifier, &error);
718 73 : if (identifier == NULL) {
719 0 : g_warning ("couldn't get item identifier: %s", egg_error_message (error));
720 0 : g_clear_error (&error);
721 0 : path = NULL;
722 :
723 : } else {
724 73 : path = gkd_secret_util_build_path (base, identifier, n_identifier);
725 73 : g_free (identifier);
726 : }
727 :
728 73 : g_free (alloc);
729 73 : return path;
730 : }
731 :
732 : static gchar *
733 25 : collection_path_for_item (GckObject *item)
734 : {
735 25 : GError *error = NULL;
736 : gpointer identifier;
737 : gsize n_identifier;
738 25 : gchar *path = NULL;
739 :
740 25 : identifier = gck_object_get_data (item, CKA_G_COLLECTION, NULL, &n_identifier, &error);
741 25 : if (!identifier) {
742 0 : g_warning ("couldn't get item collection identifier: %s", egg_error_message (error));
743 0 : g_clear_error (&error);
744 0 : return NULL;
745 : }
746 :
747 25 : path = gkd_secret_util_build_path (SECRET_COLLECTION_PREFIX, identifier, n_identifier);
748 25 : g_free (identifier);
749 25 : return path;
750 : }
751 :
752 : static gchar *
753 24 : object_path_for_collection (GckObject *collection)
754 : {
755 24 : GError *error = NULL;
756 : gpointer identifier;
757 : gsize n_identifier;
758 24 : gchar *path = NULL;
759 :
760 24 : identifier = gck_object_get_data (collection, CKA_ID, NULL, &n_identifier, &error);
761 24 : if (identifier == NULL) {
762 0 : g_warning ("couldn't get collection identifier: %s", egg_error_message (error));
763 0 : g_clear_error (&error);
764 0 : path = NULL;
765 :
766 : } else {
767 24 : path = gkd_secret_util_build_path (SECRET_COLLECTION_PREFIX, identifier, n_identifier);
768 24 : g_free (identifier);
769 : }
770 :
771 24 : return path;
772 : }
773 :
774 : static gboolean
775 2 : collection_method_create_item (GkdExportedCollection *skeleton,
776 : GDBusMethodInvocation *invocation,
777 : GVariant *properties,
778 : GVariant *secret_variant,
779 : gboolean replace,
780 : GkdSecretObjects *self)
781 : {
782 2 : GckBuilder builder = GCK_BUILDER_INIT;
783 2 : GckSession *pkcs11_session = NULL;
784 2 : GkdSecretSecret *secret = NULL;
785 2 : GckAttributes *attrs = NULL;
786 : const GckAttribute *fields;
787 2 : GckObject *item = NULL;
788 : const gchar *base;
789 2 : GError *error = NULL;
790 2 : gchar *path = NULL;
791 : gchar *identifier;
792 2 : gboolean created = FALSE;
793 : GckObject *object;
794 :
795 2 : object = secret_objects_lookup_gck_object_for_invocation (self, invocation);
796 2 : if (!object) {
797 0 : return TRUE;
798 : }
799 :
800 2 : if (!gkd_secret_property_parse_all (properties, SECRET_ITEM_INTERFACE, &builder)) {
801 0 : g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR,
802 : G_DBUS_ERROR_INVALID_ARGS,
803 : "Invalid properties argument");
804 0 : goto cleanup;
805 : }
806 :
807 2 : base = g_dbus_method_invocation_get_object_path (invocation);
808 2 : secret = gkd_secret_secret_parse (self->service, g_dbus_method_invocation_get_sender (invocation),
809 : secret_variant, &error);
810 :
811 2 : if (secret == NULL) {
812 0 : g_dbus_method_invocation_take_error (invocation, error);
813 0 : error = NULL;
814 0 : goto cleanup;
815 : }
816 :
817 2 : if (!gkd_secret_util_parse_path (base, &identifier, NULL))
818 0 : g_return_val_if_reached (FALSE);
819 2 : g_return_val_if_fail (identifier, FALSE);
820 :
821 2 : pkcs11_session = gck_object_get_session (object);
822 2 : g_return_val_if_fail (pkcs11_session, FALSE);
823 :
824 2 : attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
825 :
826 2 : if (replace) {
827 1 : fields = gck_attributes_find (attrs, CKA_G_FIELDS);
828 1 : if (fields)
829 0 : item = collection_find_matching_item (self, pkcs11_session, identifier, fields);
830 : }
831 :
832 : /* Replace the item */
833 2 : if (item) {
834 0 : if (!gck_object_set (item, attrs, NULL, &error))
835 0 : goto cleanup;
836 :
837 : /* Create a new item */
838 : } else {
839 2 : gck_builder_add_all (&builder, attrs);
840 2 : gck_builder_add_string (&builder, CKA_G_COLLECTION, identifier);
841 2 : gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
842 2 : item = gck_session_create_object (pkcs11_session, gck_builder_end (&builder), NULL, &error);
843 2 : if (item == NULL)
844 0 : goto cleanup;
845 2 : created = TRUE;
846 : }
847 :
848 : /* Set the secret */
849 2 : if (!gkd_secret_session_set_item_secret (secret->session, item, secret, &error)) {
850 0 : if (created) /* If we created, then try to destroy on failure */
851 0 : gck_object_destroy (item, NULL, NULL);
852 0 : goto cleanup;
853 : }
854 :
855 2 : path = object_path_for_item (base, item);
856 2 : gkd_secret_objects_emit_item_created (self, object, path);
857 :
858 2 : gkd_exported_collection_complete_create_item (skeleton, invocation, path, "/");
859 :
860 2 : cleanup:
861 2 : if (error) {
862 0 : if (g_error_matches (error, GCK_ERROR, CKR_USER_NOT_LOGGED_IN))
863 0 : g_dbus_method_invocation_return_error_literal (invocation, GKD_SECRET_ERROR,
864 : GKD_SECRET_ERROR_IS_LOCKED,
865 : "Cannot create an item in a locked collection");
866 : else
867 0 : g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
868 : G_DBUS_ERROR_FAILED,
869 : "Couldn't create item: %s",
870 : egg_error_message (error));
871 0 : g_clear_error (&error);
872 : }
873 :
874 2 : gkd_secret_secret_free (secret);
875 2 : gck_attributes_unref (attrs);
876 2 : if (item)
877 2 : g_object_unref (item);
878 2 : if (pkcs11_session)
879 2 : g_object_unref (pkcs11_session);
880 2 : g_free (path);
881 2 : g_object_unref (object);
882 :
883 2 : return TRUE;
884 : }
885 :
886 : static gboolean
887 1 : collection_method_delete (GkdExportedCollection *skeleton,
888 : GDBusMethodInvocation *invocation,
889 : GkdSecretObjects *self)
890 : {
891 1 : GError *error = NULL;
892 : gchar *path;
893 : GckObject *object;
894 :
895 1 : object = secret_objects_lookup_gck_object_for_invocation (self, invocation);
896 1 : if (!object) {
897 0 : return TRUE;
898 : }
899 :
900 1 : path = object_path_for_collection (object);
901 1 : g_return_val_if_fail (path != NULL, FALSE);
902 :
903 1 : if (!gck_object_destroy (object, NULL, &error)) {
904 0 : g_dbus_method_invocation_return_error (invocation,
905 : G_DBUS_ERROR,
906 : G_DBUS_ERROR_FAILED,
907 : "Couldn't delete collection: %s",
908 : egg_error_message (error));
909 0 : g_clear_error (&error);
910 0 : goto cleanup;
911 : }
912 :
913 : /* Notify the callers that a collection was deleted */
914 1 : gkd_secret_service_emit_collection_deleted (self->service, path);
915 1 : gkd_exported_collection_complete_delete (skeleton, invocation, "/");
916 :
917 1 : cleanup:
918 1 : g_free (path);
919 1 : g_object_unref (object);
920 :
921 1 : return TRUE;
922 : }
923 :
924 : /* -----------------------------------------------------------------------------
925 : * OBJECT
926 : */
927 :
928 : static void
929 75 : skeleton_destroy_func (gpointer user_data)
930 : {
931 75 : GDBusInterfaceSkeleton *skeleton = user_data;
932 75 : g_dbus_interface_skeleton_unexport (skeleton);
933 75 : g_object_unref (skeleton);
934 75 : }
935 :
936 : static void
937 25 : gkd_secret_objects_init (GkdSecretObjects *self)
938 : {
939 25 : self->collections_to_skeletons = g_hash_table_new_full (g_str_hash, g_str_equal,
940 : g_free, skeleton_destroy_func);
941 25 : self->items_to_skeletons = g_hash_table_new_full (g_str_hash, g_str_equal,
942 : g_free, skeleton_destroy_func);
943 25 : }
944 :
945 : static void
946 50 : gkd_secret_objects_dispose (GObject *obj)
947 : {
948 50 : GkdSecretObjects *self = GKD_SECRET_OBJECTS (obj);
949 :
950 50 : if (self->pkcs11_slot) {
951 25 : g_object_unref (self->pkcs11_slot);
952 25 : self->pkcs11_slot = NULL;
953 : }
954 :
955 50 : if (self->service) {
956 25 : g_object_remove_weak_pointer (G_OBJECT (self->service),
957 25 : (gpointer*)&(self->service));
958 25 : self->service = NULL;
959 : }
960 :
961 50 : g_clear_pointer (&self->collections_to_skeletons, g_hash_table_unref);
962 50 : g_clear_pointer (&self->items_to_skeletons, g_hash_table_unref);
963 :
964 50 : G_OBJECT_CLASS (gkd_secret_objects_parent_class)->dispose (obj);
965 50 : }
966 :
967 : static void
968 50 : gkd_secret_objects_set_property (GObject *obj, guint prop_id, const GValue *value,
969 : GParamSpec *pspec)
970 : {
971 50 : GkdSecretObjects *self = GKD_SECRET_OBJECTS (obj);
972 :
973 50 : switch (prop_id) {
974 25 : case PROP_PKCS11_SLOT:
975 25 : g_return_if_fail (!self->pkcs11_slot);
976 25 : self->pkcs11_slot = g_value_dup_object (value);
977 25 : g_return_if_fail (self->pkcs11_slot);
978 25 : break;
979 25 : case PROP_SERVICE:
980 25 : g_return_if_fail (!self->service);
981 25 : self->service = g_value_get_object (value);
982 25 : g_return_if_fail (self->service);
983 25 : g_object_add_weak_pointer (G_OBJECT (self->service),
984 25 : (gpointer*)&(self->service));
985 25 : break;
986 0 : default:
987 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
988 0 : break;
989 : }
990 : }
991 :
992 : static void
993 0 : gkd_secret_objects_get_property (GObject *obj, guint prop_id, GValue *value,
994 : GParamSpec *pspec)
995 : {
996 0 : GkdSecretObjects *self = GKD_SECRET_OBJECTS (obj);
997 :
998 0 : switch (prop_id) {
999 0 : case PROP_PKCS11_SLOT:
1000 0 : g_value_set_object (value, gkd_secret_objects_get_pkcs11_slot (self));
1001 0 : break;
1002 0 : case PROP_SERVICE:
1003 0 : g_value_set_object (value, self->service);
1004 0 : break;
1005 0 : default:
1006 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1007 0 : break;
1008 : }
1009 0 : }
1010 :
1011 : static void
1012 25 : gkd_secret_objects_class_init (GkdSecretObjectsClass *klass)
1013 : {
1014 25 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1015 :
1016 25 : gobject_class->dispose = gkd_secret_objects_dispose;
1017 25 : gobject_class->set_property = gkd_secret_objects_set_property;
1018 25 : gobject_class->get_property = gkd_secret_objects_get_property;
1019 :
1020 25 : g_object_class_install_property (gobject_class, PROP_PKCS11_SLOT,
1021 : g_param_spec_object ("pkcs11-slot", "Pkcs11 Slot", "PKCS#11 slot that we use for secrets",
1022 : GCK_TYPE_SLOT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1023 :
1024 25 : g_object_class_install_property (gobject_class, PROP_SERVICE,
1025 : g_param_spec_object ("service", "Service", "Service which owns this objects",
1026 : GKD_SECRET_TYPE_SERVICE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1027 25 : }
1028 :
1029 : /* -----------------------------------------------------------------------------
1030 : * PUBLIC
1031 : */
1032 :
1033 : GckSlot*
1034 41 : gkd_secret_objects_get_pkcs11_slot (GkdSecretObjects *self)
1035 : {
1036 41 : g_return_val_if_fail (GKD_SECRET_IS_OBJECTS (self), NULL);
1037 41 : return self->pkcs11_slot;
1038 : }
1039 :
1040 : GckObject*
1041 23 : gkd_secret_objects_lookup_collection (GkdSecretObjects *self, const gchar *caller,
1042 : const gchar *path)
1043 : {
1044 23 : GckBuilder builder = GCK_BUILDER_INIT;
1045 23 : GckObject *object = NULL;
1046 23 : GError *error = NULL;
1047 : GList *objects;
1048 : GckSession *session;
1049 : gchar *identifier;
1050 : const gchar *real_identifier;
1051 :
1052 23 : g_return_val_if_fail (GKD_SECRET_IS_OBJECTS (self), NULL);
1053 23 : g_return_val_if_fail (path, NULL);
1054 :
1055 23 : if (!gkd_secret_util_parse_path (path, &identifier, NULL))
1056 0 : return NULL;
1057 :
1058 23 : if (g_str_has_prefix (path, SECRET_ALIAS_PREFIX))
1059 0 : real_identifier = gkd_secret_service_get_alias (self->service, identifier);
1060 : else
1061 23 : real_identifier = identifier;
1062 :
1063 : /* The session we're using to access the object */
1064 23 : if (caller == NULL)
1065 1 : session = gkd_secret_service_internal_pkcs11_session (self->service);
1066 : else
1067 22 : session = gkd_secret_service_get_pkcs11_session (self->service, caller);
1068 23 : g_return_val_if_fail (session, NULL);
1069 :
1070 23 : gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_COLLECTION);
1071 23 : gck_builder_add_string (&builder, CKA_ID, real_identifier);
1072 :
1073 23 : objects = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);
1074 :
1075 23 : g_free (identifier);
1076 :
1077 23 : if (error != NULL) {
1078 0 : g_warning ("couldn't lookup collection: %s: %s", path, egg_error_message (error));
1079 0 : g_clear_error (&error);
1080 : }
1081 :
1082 23 : if (objects)
1083 23 : object = g_object_ref (objects->data);
1084 :
1085 23 : gck_list_unref_free (objects);
1086 23 : return object;
1087 : }
1088 :
1089 : GckObject*
1090 0 : gkd_secret_objects_lookup_item (GkdSecretObjects *self, const gchar *caller,
1091 : const gchar *path)
1092 : {
1093 0 : GckBuilder builder = GCK_BUILDER_INIT;
1094 0 : GckObject *object = NULL;
1095 0 : GError *error = NULL;
1096 : GList *objects;
1097 : GckSession *session;
1098 : gchar *collection;
1099 : gchar *identifier;
1100 :
1101 0 : g_return_val_if_fail (GKD_SECRET_IS_OBJECTS (self), NULL);
1102 0 : g_return_val_if_fail (caller, NULL);
1103 0 : g_return_val_if_fail (path, NULL);
1104 :
1105 0 : if (!gkd_secret_util_parse_path (path, &collection, &identifier))
1106 0 : return NULL;
1107 :
1108 : /* The session we're using to access the object */
1109 0 : session = gkd_secret_service_get_pkcs11_session (self->service, caller);
1110 0 : g_return_val_if_fail (session, NULL);
1111 :
1112 0 : gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
1113 0 : gck_builder_add_string (&builder, CKA_ID, identifier);
1114 0 : gck_builder_add_string (&builder, CKA_G_COLLECTION, collection);
1115 :
1116 0 : objects = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);
1117 :
1118 0 : g_free (identifier);
1119 0 : g_free (collection);
1120 :
1121 0 : if (error != NULL) {
1122 0 : g_warning ("couldn't lookup item: %s: %s", path, egg_error_message (error));
1123 0 : g_clear_error (&error);
1124 : }
1125 :
1126 0 : if (objects)
1127 0 : object = g_object_ref (objects->data);
1128 :
1129 0 : gck_list_unref_free (objects);
1130 0 : return object;
1131 : }
1132 :
1133 : static void
1134 76 : objects_foreach_item (GkdSecretObjects *self,
1135 : GList *items,
1136 : const gchar *base,
1137 : GkdSecretObjectsForeach callback,
1138 : gpointer user_data)
1139 : {
1140 : gchar *path;
1141 : GList *l;
1142 :
1143 125 : for (l = items; l; l = g_list_next (l)) {
1144 49 : path = object_path_for_item (base, l->data);
1145 49 : (callback) (self, path, l->data, user_data);
1146 49 : g_free (path);
1147 : }
1148 76 : }
1149 :
1150 : void
1151 73 : gkd_secret_objects_foreach_item (GkdSecretObjects *self,
1152 : const gchar *caller,
1153 : const gchar *base,
1154 : GkdSecretObjectsForeach callback,
1155 : gpointer user_data)
1156 : {
1157 73 : GckBuilder builder = GCK_BUILDER_INIT;
1158 : GckSession *session;
1159 73 : GError *error = NULL;
1160 : gchar *identifier;
1161 : GList *items;
1162 :
1163 73 : g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
1164 73 : g_return_if_fail (base != NULL);
1165 73 : g_return_if_fail (callback != NULL);
1166 :
1167 : /* The session we're using to access the object */
1168 73 : if (caller == NULL) {
1169 73 : session = gkd_secret_service_internal_pkcs11_session (self->service);
1170 : } else {
1171 0 : session = gkd_secret_service_get_pkcs11_session (self->service, caller);
1172 : }
1173 :
1174 73 : if (!gkd_secret_util_parse_path (base, &identifier, NULL))
1175 0 : g_return_if_reached ();
1176 :
1177 73 : gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
1178 73 : gck_builder_add_string (&builder, CKA_G_COLLECTION, identifier);
1179 :
1180 73 : items = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);
1181 :
1182 73 : if (error == NULL) {
1183 73 : objects_foreach_item (self, items, base, callback, user_data);
1184 :
1185 : } else {
1186 0 : g_warning ("couldn't lookup items in '%s' collection: %s", identifier, egg_error_message (error));
1187 0 : g_clear_error (&error);
1188 : }
1189 :
1190 73 : gck_list_unref_free (items);
1191 73 : g_free (identifier);
1192 : }
1193 :
1194 : void
1195 28 : gkd_secret_objects_foreach_collection (GkdSecretObjects *self,
1196 : const gchar *caller,
1197 : GkdSecretObjectsForeach callback,
1198 : gpointer user_data)
1199 : {
1200 28 : GckBuilder builder = GCK_BUILDER_INIT;
1201 : GckSession *session;
1202 28 : GError *error = NULL;
1203 : GList *collections, *l;
1204 : gpointer identifier;
1205 : gsize n_identifier;
1206 : gchar *path;
1207 :
1208 28 : g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
1209 28 : g_return_if_fail (callback);
1210 :
1211 : /* The session we're using to access the object */
1212 28 : if (caller == NULL) {
1213 28 : session = gkd_secret_service_internal_pkcs11_session (self->service);
1214 : } else {
1215 0 : session = gkd_secret_service_get_pkcs11_session (self->service, caller);
1216 : }
1217 :
1218 28 : gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_COLLECTION);
1219 :
1220 28 : collections = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);
1221 :
1222 28 : if (error != NULL) {
1223 0 : g_warning ("couldn't lookup collections: %s", egg_error_message (error));
1224 0 : g_clear_error (&error);
1225 0 : return;
1226 : }
1227 :
1228 83 : for (l = collections; l; l = g_list_next (l)) {
1229 55 : identifier = gck_object_get_data (l->data, CKA_ID, NULL, &n_identifier, &error);
1230 55 : if (identifier == NULL) {
1231 0 : g_warning ("couldn't get collection identifier: %s", egg_error_message (error));
1232 0 : g_clear_error (&error);
1233 0 : continue;
1234 : }
1235 :
1236 55 : path = gkd_secret_util_build_path (SECRET_COLLECTION_PREFIX, identifier, n_identifier);
1237 55 : g_free (identifier);
1238 :
1239 55 : (callback) (self, path, l->data, user_data);
1240 55 : g_free (path);
1241 : }
1242 :
1243 28 : gck_list_unref_free (collections);
1244 : }
1245 :
1246 : GVariant *
1247 28 : gkd_secret_objects_append_collection_paths (GkdSecretObjects *self,
1248 : const gchar *caller)
1249 : {
1250 : GVariantBuilder builder;
1251 :
1252 28 : g_return_val_if_fail (GKD_SECRET_IS_OBJECTS (self), NULL);
1253 :
1254 28 : g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
1255 28 : gkd_secret_objects_foreach_collection (self, caller, on_object_path_append_to_builder, &builder);
1256 :
1257 28 : return g_variant_builder_end (&builder);
1258 : }
1259 :
1260 : gboolean
1261 2 : gkd_secret_objects_handle_search_items (GkdSecretObjects *self,
1262 : GDBusMethodInvocation *invocation,
1263 : GVariant *attributes,
1264 : const gchar *base,
1265 : gboolean separate_locked)
1266 : {
1267 2 : GckBuilder builder = GCK_BUILDER_INIT;
1268 : GckObject *search;
1269 : GckSession *session;
1270 2 : GError *error = NULL;
1271 : gchar *identifier;
1272 : gpointer data;
1273 : gsize n_data;
1274 : GList *locked, *unlocked;
1275 : GList *items;
1276 : GVariantBuilder result;
1277 :
1278 2 : if (!gkd_secret_property_parse_fields (attributes, &builder)) {
1279 0 : gck_builder_clear (&builder);
1280 0 : g_dbus_method_invocation_return_error_literal (invocation,
1281 : G_DBUS_ERROR,
1282 : G_DBUS_ERROR_FAILED,
1283 : "Invalid data in attributes argument");
1284 0 : return TRUE;
1285 : }
1286 :
1287 2 : if (base != NULL) {
1288 1 : if (!gkd_secret_util_parse_path (base, &identifier, NULL))
1289 0 : g_return_val_if_reached (FALSE);
1290 1 : gck_builder_add_string (&builder, CKA_G_COLLECTION, identifier);
1291 1 : g_free (identifier);
1292 : }
1293 :
1294 2 : gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_SEARCH);
1295 2 : gck_builder_add_boolean (&builder, CKA_TOKEN, FALSE);
1296 :
1297 : /* The session we're using to access the object */
1298 2 : session = gkd_secret_service_get_pkcs11_session (self->service, g_dbus_method_invocation_get_sender (invocation));
1299 2 : g_return_val_if_fail (session, FALSE);
1300 :
1301 : /* Create the search object */
1302 2 : search = gck_session_create_object (session, gck_builder_end (&builder), NULL, &error);
1303 :
1304 2 : if (error != NULL) {
1305 0 : g_dbus_method_invocation_return_error (invocation,
1306 : G_DBUS_ERROR,
1307 : G_DBUS_ERROR_FAILED,
1308 : "Couldn't search for items: %s",
1309 : egg_error_message (error));
1310 0 : g_clear_error (&error);
1311 0 : return TRUE;
1312 : }
1313 :
1314 : /* Get the matched item handles, and delete the search object */
1315 2 : data = gck_object_get_data (search, CKA_G_MATCHED, NULL, &n_data, &error);
1316 2 : gck_object_destroy (search, NULL, NULL);
1317 2 : g_object_unref (search);
1318 :
1319 2 : if (error != NULL) {
1320 0 : g_dbus_method_invocation_return_error (invocation,
1321 : G_DBUS_ERROR,
1322 : G_DBUS_ERROR_FAILED,
1323 : "Couldn't retrieve matched items: %s",
1324 : egg_error_message (error));
1325 0 : g_clear_error (&error);
1326 0 : return TRUE;
1327 : }
1328 :
1329 : /* Build a list of object handles */
1330 2 : items = gck_objects_from_handle_array (session, data, n_data / sizeof (CK_OBJECT_HANDLE));
1331 2 : g_free (data);
1332 :
1333 : /* Filter out the locked items */
1334 2 : if (separate_locked) {
1335 : GVariant *unlocked_variant, *locked_variant;
1336 :
1337 1 : item_cleanup_search_results (session, items, &locked, &unlocked);
1338 :
1339 1 : g_variant_builder_init (&result, G_VARIANT_TYPE ("ao"));
1340 1 : objects_foreach_item (self, unlocked, NULL, on_object_path_append_to_builder, &result);
1341 1 : unlocked_variant = g_variant_builder_end (&result);
1342 :
1343 1 : g_variant_builder_init (&result, G_VARIANT_TYPE ("ao"));
1344 1 : objects_foreach_item (self, locked, NULL, on_object_path_append_to_builder, &result);
1345 1 : locked_variant = g_variant_builder_end (&result);
1346 :
1347 1 : g_list_free (locked);
1348 1 : g_list_free (unlocked);
1349 :
1350 1 : g_dbus_method_invocation_return_value (invocation,
1351 : g_variant_new ("(@ao@ao)",
1352 : unlocked_variant,
1353 : locked_variant));
1354 : } else {
1355 1 : g_variant_builder_init (&result, G_VARIANT_TYPE ("ao"));
1356 1 : objects_foreach_item (self, items, NULL, on_object_path_append_to_builder, &result);
1357 :
1358 1 : g_dbus_method_invocation_return_value (invocation,
1359 : g_variant_new ("(@ao)", g_variant_builder_end (&result)));
1360 : }
1361 :
1362 2 : gck_list_unref_free (items);
1363 :
1364 2 : return TRUE;
1365 : }
1366 :
1367 : gboolean
1368 0 : gkd_secret_objects_handle_get_secrets (GkdSecretObjects *self,
1369 : GDBusMethodInvocation *invocation,
1370 : const gchar **paths,
1371 : const gchar *session_path)
1372 : {
1373 : GkdSecretSession *session;
1374 : GkdSecretSecret *secret;
1375 : GckObject *item;
1376 : const char *caller;
1377 : int i;
1378 : GVariantBuilder builder;
1379 0 : GError *error = NULL;
1380 :
1381 0 : caller = g_dbus_method_invocation_get_sender (invocation);
1382 0 : session = gkd_secret_service_lookup_session (self->service, session_path, caller);
1383 0 : if (session == NULL) {
1384 0 : g_dbus_method_invocation_return_error_literal (invocation, GKD_SECRET_ERROR,
1385 : GKD_SECRET_ERROR_NO_SESSION,
1386 : "The session does not exist");
1387 0 : return TRUE;
1388 : }
1389 :
1390 0 : g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{o(oayays)}"));
1391 :
1392 0 : for (i = 0; paths[i] != NULL; ++i) {
1393 :
1394 : /* Try to find the item, if it doesn't exist, just ignore */
1395 0 : item = gkd_secret_objects_lookup_item (self, caller, paths[i]);
1396 0 : if (!item)
1397 0 : continue;
1398 :
1399 0 : secret = gkd_secret_session_get_item_secret (session, item, &error);
1400 0 : g_object_unref (item);
1401 :
1402 0 : if (secret == NULL) {
1403 : /* We ignore is locked, and just leave out from response */
1404 0 : if (g_error_matches (error, GKD_SECRET_ERROR, GKD_SECRET_ERROR_IS_LOCKED)) {
1405 0 : g_clear_error (&error);
1406 0 : continue;
1407 :
1408 : /* All other errors stop the operation */
1409 : } else {
1410 0 : g_dbus_method_invocation_take_error (invocation, error);
1411 0 : return TRUE;
1412 : }
1413 : }
1414 :
1415 0 : g_variant_builder_add (&builder, "{o@(oayays)}", paths[i], gkd_secret_secret_append (secret));
1416 0 : gkd_secret_secret_free (secret);
1417 : }
1418 :
1419 0 : g_dbus_method_invocation_return_value (invocation,
1420 : g_variant_new ("(@a{o(oayays)})", g_variant_builder_end (&builder)));
1421 0 : return TRUE;
1422 : }
1423 :
1424 : static void
1425 20 : on_each_item_emit_locked (GkdSecretObjects *self,
1426 : const gchar *path,
1427 : GckObject *object,
1428 : gpointer user_data)
1429 : {
1430 : GkdExportedItem *skeleton;
1431 : GVariant *value;
1432 20 : GError *error = NULL;
1433 :
1434 20 : skeleton = g_hash_table_lookup (self->items_to_skeletons, path);
1435 20 : if (skeleton == NULL) {
1436 0 : g_warning ("setting locked state on item %s, but no skeleton found", path);
1437 0 : return;
1438 : }
1439 :
1440 20 : value = object_property_get (self, object, "Locked", &error);
1441 20 : if (!value) {
1442 0 : g_warning ("setting locked state on item %s, but no property value: %s",
1443 : path, error->message);
1444 0 : g_error_free (error);
1445 0 : return;
1446 : }
1447 :
1448 20 : gkd_exported_item_set_locked (skeleton, g_variant_get_boolean (value));
1449 20 : g_variant_unref (value);
1450 :
1451 20 : gkd_secret_objects_emit_item_changed (self, object);
1452 : }
1453 :
1454 : void
1455 20 : gkd_secret_objects_emit_collection_locked (GkdSecretObjects *self,
1456 : GckObject *collection)
1457 : {
1458 : gchar *collection_path;
1459 : GkdExportedCollection *skeleton;
1460 : GVariant *value;
1461 20 : GError *error = NULL;
1462 :
1463 20 : collection_path = object_path_for_collection (collection);
1464 20 : gkd_secret_objects_foreach_item (self, NULL, collection_path,
1465 : on_each_item_emit_locked, NULL);
1466 :
1467 20 : skeleton = g_hash_table_lookup (self->collections_to_skeletons, collection_path);
1468 20 : if (skeleton == NULL) {
1469 0 : g_warning ("setting locked state on collection %s, but no skeleton found", collection_path);
1470 0 : return;
1471 : }
1472 :
1473 20 : value = object_property_get (self, collection, "Locked", &error);
1474 20 : if (!value) {
1475 0 : g_warning ("setting locked state on item %s, but no property value: %s",
1476 : collection_path, error->message);
1477 0 : g_error_free (error);
1478 0 : return;
1479 : }
1480 :
1481 20 : gkd_exported_collection_set_locked (skeleton, g_variant_get_boolean (value));
1482 20 : g_variant_unref (value);
1483 :
1484 20 : gkd_secret_service_emit_collection_changed (self->service, collection_path);
1485 20 : g_free (collection_path);
1486 : }
1487 :
1488 : static void
1489 25 : gkd_secret_objects_register_item (GkdSecretObjects *self,
1490 : const gchar *item_path)
1491 : {
1492 : GkdExportedItem *skeleton;
1493 25 : GError *error = NULL;
1494 :
1495 25 : skeleton = g_hash_table_lookup (self->items_to_skeletons, item_path);
1496 25 : if (skeleton != NULL) {
1497 0 : g_warning ("asked to register item %s, but it's already registered", item_path);
1498 0 : return;
1499 : }
1500 :
1501 25 : skeleton = gkd_secret_item_skeleton_new (self);
1502 25 : g_hash_table_insert (self->items_to_skeletons, g_strdup (item_path), skeleton);
1503 :
1504 25 : g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (skeleton),
1505 : gkd_secret_service_get_connection (self->service),
1506 : item_path, &error);
1507 25 : if (error != NULL) {
1508 0 : g_warning ("could not register secret item on session bus: %s", error->message);
1509 0 : g_error_free (error);
1510 : }
1511 :
1512 25 : g_signal_connect (skeleton, "handle-delete",
1513 : G_CALLBACK (item_method_delete), self);
1514 25 : g_signal_connect (skeleton, "handle-get-secret",
1515 : G_CALLBACK (item_method_get_secret), self);
1516 25 : g_signal_connect (skeleton, "handle-set-secret",
1517 : G_CALLBACK (item_method_set_secret), self);
1518 : }
1519 :
1520 : static void
1521 1 : gkd_secret_objects_unregister_item (GkdSecretObjects *self,
1522 : const gchar *item_path)
1523 : {
1524 1 : if (!g_hash_table_remove (self->items_to_skeletons, item_path)) {
1525 0 : g_warning ("asked to unregister item %s, but it wasn't found", item_path);
1526 0 : return;
1527 : }
1528 : }
1529 :
1530 : void
1531 2 : gkd_secret_objects_emit_item_created (GkdSecretObjects *self,
1532 : GckObject *collection,
1533 : const gchar *item_path)
1534 : {
1535 : GkdExportedCollection *skeleton;
1536 : gchar *collection_path;
1537 : gchar **items;
1538 :
1539 2 : g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
1540 2 : g_return_if_fail (GCK_OBJECT (collection));
1541 2 : g_return_if_fail (item_path != NULL);
1542 :
1543 2 : collection_path = object_path_for_collection (collection);
1544 2 : skeleton = g_hash_table_lookup (self->collections_to_skeletons, collection_path);
1545 2 : g_return_if_fail (skeleton != NULL);
1546 :
1547 2 : gkd_secret_objects_register_item (self, item_path);
1548 2 : gkd_exported_collection_emit_item_created (skeleton, item_path);
1549 :
1550 2 : items = gkd_secret_objects_get_collection_items (self, collection_path);
1551 2 : gkd_exported_collection_set_items (skeleton, (const gchar **) items);
1552 :
1553 2 : g_free (collection_path);
1554 2 : g_strfreev (items);
1555 : }
1556 :
1557 : void
1558 21 : gkd_secret_objects_emit_item_changed (GkdSecretObjects *self,
1559 : GckObject *item)
1560 : {
1561 : GkdExportedCollection *skeleton;
1562 : gchar *collection_path;
1563 : gchar *item_path;
1564 :
1565 21 : g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
1566 21 : g_return_if_fail (GCK_OBJECT (item));
1567 :
1568 21 : collection_path = collection_path_for_item (item);
1569 21 : skeleton = g_hash_table_lookup (self->collections_to_skeletons, collection_path);
1570 21 : g_return_if_fail (skeleton != NULL);
1571 :
1572 21 : item_path = object_path_for_item (collection_path, item);
1573 21 : gkd_exported_collection_emit_item_changed (skeleton, item_path);
1574 :
1575 21 : g_free (item_path);
1576 21 : g_free (collection_path);
1577 : }
1578 :
1579 : void
1580 1 : gkd_secret_objects_emit_item_deleted (GkdSecretObjects *self,
1581 : GckObject *collection,
1582 : const gchar *item_path)
1583 : {
1584 : GkdExportedCollection *skeleton;
1585 : gchar *collection_path;
1586 : gchar **items;
1587 :
1588 1 : g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
1589 1 : g_return_if_fail (GCK_OBJECT (collection));
1590 1 : g_return_if_fail (item_path != NULL);
1591 :
1592 1 : collection_path = object_path_for_collection (collection);
1593 1 : skeleton = g_hash_table_lookup (self->collections_to_skeletons, collection_path);
1594 1 : g_return_if_fail (skeleton != NULL);
1595 :
1596 1 : gkd_secret_objects_unregister_item (self, item_path);
1597 1 : gkd_exported_collection_emit_item_deleted (skeleton, item_path);
1598 :
1599 1 : items = gkd_secret_objects_get_collection_items (self, collection_path);
1600 1 : gkd_exported_collection_set_items (skeleton, (const gchar **) items);
1601 :
1602 1 : g_strfreev (items);
1603 1 : g_free (collection_path);
1604 : }
1605 :
1606 : static void
1607 50 : gkd_secret_objects_init_collection_items (GkdSecretObjects *self,
1608 : const gchar *collection_path)
1609 : {
1610 : gchar **items;
1611 : gint idx;
1612 :
1613 50 : items = gkd_secret_objects_get_collection_items (self, collection_path);
1614 73 : for (idx = 0; items[idx] != NULL; idx++)
1615 23 : gkd_secret_objects_register_item (self, items[idx]);
1616 :
1617 50 : g_strfreev (items);
1618 50 : }
1619 :
1620 : void
1621 50 : gkd_secret_objects_register_collection (GkdSecretObjects *self,
1622 : const gchar *collection_path)
1623 : {
1624 : GkdExportedCollection *skeleton;
1625 50 : GError *error = NULL;
1626 :
1627 50 : skeleton = g_hash_table_lookup (self->collections_to_skeletons, collection_path);
1628 50 : if (skeleton != NULL) {
1629 0 : g_warning ("asked to register collection %s, but it's already registered", collection_path);
1630 0 : return;
1631 : }
1632 :
1633 50 : skeleton = gkd_secret_collection_skeleton_new (self);
1634 50 : g_hash_table_insert (self->collections_to_skeletons, g_strdup (collection_path), skeleton);
1635 :
1636 50 : g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (skeleton),
1637 : gkd_secret_service_get_connection (self->service),
1638 : collection_path, &error);
1639 50 : if (error != NULL) {
1640 0 : g_warning ("could not register secret collection on session bus: %s", error->message);
1641 0 : g_error_free (error);
1642 : }
1643 :
1644 50 : g_signal_connect (skeleton, "handle-create-item",
1645 : G_CALLBACK (collection_method_create_item), self);
1646 50 : g_signal_connect (skeleton, "handle-delete",
1647 : G_CALLBACK (collection_method_delete), self);
1648 50 : g_signal_connect (skeleton, "handle-search-items",
1649 : G_CALLBACK (collection_method_search_items), self);
1650 :
1651 50 : gkd_secret_objects_init_collection_items (self, collection_path);
1652 : }
1653 :
1654 : void
1655 1 : gkd_secret_objects_unregister_collection (GkdSecretObjects *self,
1656 : const gchar *collection_path)
1657 : {
1658 1 : if (!g_hash_table_remove (self->collections_to_skeletons, collection_path)) {
1659 0 : g_warning ("asked to unregister collection %s, but it wasn't found", collection_path);
1660 0 : return;
1661 : }
1662 : }
|