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