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