示例#1
0
gboolean
gkd_secret_lock (GckObject *collection, DBusError *derr)
{
	GckBuilder builder = GCK_BUILDER_INIT;
	GError *error = NULL;
	GList *objects, *l;
	GckSession *session;

	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_CREDENTIAL);
	gck_builder_add_ulong (&builder, CKA_G_OBJECT, gck_object_get_handle (collection));

	session = gck_object_get_session (collection);
	g_return_val_if_fail (session, FALSE);

	objects = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);

	g_object_unref (session);

	if (error != NULL) {
		g_warning ("couldn't search for credential objects: %s", egg_error_message (error));
		dbus_set_error (derr, DBUS_ERROR_FAILED, "Couldn't lock collection");
		g_clear_error (&error);
		return FALSE;
	}

	for (l = objects; l; l = g_list_next (l)) {
		if (!gck_object_destroy (l->data, NULL, &error)) {
			g_warning ("couldn't destroy credential object: %s", egg_error_message (error));
			g_clear_error (&error);
		}
	}

	gck_list_unref_free (objects);
	return TRUE;
}
示例#2
0
static GckSlot*
calculate_secrets_slot (void)
{
	GckSlot *slot = NULL;
	GckModule *module;
	GList *modules;
	GError *err = NULL;
	CK_FUNCTION_LIST_PTR funcs;

	/* TODO: Should we be handling just one module here? */
	funcs = gkd_pkcs11_get_functions ();
	g_return_val_if_fail (funcs != NULL, NULL);

	module = gck_module_new (funcs);
	g_return_val_if_fail (module, NULL);

	modules = g_list_prepend (NULL, module);
	slot = gck_modules_token_for_uri (modules, "pkcs11:token=Secret%20Store", &err);
	if (!slot && err) {
		g_warning ("couldn't find secret store: %s", egg_error_message (err));
		g_clear_error (&err);
	}

	gck_list_unref_free (modules);
	return slot;
}
示例#3
0
static gboolean
init_pin_for_uninitialized_slots (GList *modules, const gchar *master)
{
	GError *error = NULL;
	GList *slots, *l;
	gboolean initialize;
	GckTokenInfo *info;
	GckSession *session;

	g_return_val_if_fail (master, FALSE);

	slots = gck_modules_get_slots (modules, TRUE);
	for (l = slots; l; l = g_list_next (l)) {
		info = gck_slot_get_token_info (l->data);
		initialize = (info && !(info->flags & CKF_USER_PIN_INITIALIZED));

		if (initialize) {
			session = open_and_login_session (l->data, CKU_SO, NULL);
			if (session != NULL) {
				if (!gck_session_init_pin (session, (const guchar*)master, strlen (master), NULL, &error)) {
					if (!g_error_matches (error, GCK_ERROR, CKR_FUNCTION_NOT_SUPPORTED))
						g_warning ("couldn't initialize slot with master password: %s",
						           egg_error_message (error));
					g_clear_error (&error);
				}
				g_object_unref (session);
			}
		}

		gck_token_info_free (info);
	}
	gck_list_unref_free (slots);
	return TRUE;
}
static void
imported_display (GcrImporter *importer)
{
	GParamSpec *spec;
	gchar *label = NULL;

	spec = g_object_class_find_property (G_OBJECT_GET_CLASS (importer), "imported");
	if (spec == NULL)
		return;

	g_object_get (importer, "label", &label, NULL);

	if (spec->value_type == GCK_TYPE_LIST) {
		GList *list, *l;
		g_object_get (importer, "imported", &list, NULL);
		for (l = list; l != NULL; l = g_list_next (l))
			imported_object (l->data, label);
		gck_list_unref_free (list);

	} else if (spec->value_type == G_TYPE_STRV) {
		gchar **fingerprints;
		guint i;
		g_object_get (importer, "imported", &fingerprints, NULL);
		for (i = 0; fingerprints && fingerprints[i] != NULL; i++)
			imported_fingerprint (fingerprints[i], label);
		g_strfreev (fingerprints);
	}
}
示例#5
0
static GckObject*
lookup_login_keyring (GckSession *session)
{
	GckAttributes *atts;
	GError *error = NULL;
	GckObject *login = NULL;
	GList *objects;
	guint length;

	g_return_val_if_fail (GCK_IS_SESSION (session), NULL);

	atts = gck_attributes_new ();
	gck_attributes_add_ulong (atts, CKA_CLASS, CKO_G_COLLECTION);
	gck_attributes_add_boolean (atts, CKA_TOKEN, TRUE);
	gck_attributes_add_string (atts, CKA_ID, "login");

	objects = gck_session_find_objects (session, atts, NULL, &error);
	gck_attributes_unref (atts);

	if (error) {
		g_warning ("couldn't search for login keyring: %s", egg_error_message (error));
		g_clear_error (&error);
		return NULL;
	}

	length = g_list_length (objects);
	if (length == 1)
		login = g_object_ref (objects->data);
	else if (length > 1)
		g_warning ("more than one login keyring exists");

	gck_list_unref_free (objects);
	return login;
}
static GckObject *
secret_objects_lookup_gck_object_for_path (GkdSecretObjects *self,
					   const gchar *sender,
					   const gchar *path,
					   GError **error_out)
{
	GckBuilder builder = GCK_BUILDER_INIT;
	GList *objects;
	GckSession *session;
	gchar *c_ident;
	gchar *i_ident;
	GckObject *object = NULL;
	GError *error = NULL;

	g_return_val_if_fail (path, FALSE);

	if (!gkd_secret_util_parse_path (path, &c_ident, &i_ident) || !c_ident)
		goto out;

	/* The session we're using to access the object */
	session = gkd_secret_service_get_pkcs11_session (self->service, sender);
	g_return_val_if_fail (session, FALSE);

	if (i_ident) {
		gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
		gck_builder_add_string (&builder, CKA_G_COLLECTION, c_ident);
		gck_builder_add_string (&builder, CKA_ID, i_ident);
	} else {
		gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_COLLECTION);
		gck_builder_add_string (&builder, CKA_ID, c_ident);
	}

	objects = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);

	g_free (c_ident);
	g_free (i_ident);

	if (error != NULL) {
		g_warning ("couldn't lookup object: %s: %s", path, egg_error_message (error));
		g_clear_error (&error);
	}

	if (!objects)
		goto out;

	object = g_object_ref (objects->data);
	gck_list_unref_free (objects);

 out:
	if (!object)
		g_set_error (error_out, GKD_SECRET_ERROR,
			     GKD_SECRET_ERROR_NO_SUCH_OBJECT,
			     "The '%s' object does not exist",
			     path);

	return object;
}
示例#7
0
static gpointer
run_client_thread (gpointer data)
{
	gint *socket = data;
	GkdSshAgentCall call;
	EggBuffer req;
	EggBuffer resp;
	guchar op;

	memset (&call, 0, sizeof (call));
	call.sock = g_atomic_int_get (socket);
	g_assert (call.sock != -1);

	egg_buffer_init_full (&req, 128, egg_secure_realloc);
	egg_buffer_init_full (&resp, 128, (EggBufferAllocator)g_realloc);
	call.req = &req;
	call.resp = &resp;
	call.modules = gck_list_ref_copy (pkcs11_modules);

	for (;;) {

		egg_buffer_reset (call.req);

		/* 1. Read in the request */
		if (!read_packet_with_size (&call))
			break;

		/* 2. Now decode the operation */
		if (!egg_buffer_get_byte (call.req, 4, NULL, &op))
			break;
		if (op >= GKD_SSH_OP_MAX)
			break;
		g_assert (gkd_ssh_agent_operations[op]);

		/* 3. Execute the right operation */
		egg_buffer_reset (call.resp);
		egg_buffer_add_uint32 (call.resp, 0);
		if (!(gkd_ssh_agent_operations[op]) (&call))
			break;
		if (!egg_buffer_set_uint32 (call.resp, 0, call.resp->len - 4))
			break;

		/* 4. Write the reply back out */
		if (!write_all (call.sock, call.resp->buf, call.resp->len))
			break;
	}

	egg_buffer_uninit (&req);
	egg_buffer_uninit (&resp);
	gck_list_unref_free (call.modules);
	call.modules = NULL;

	close (call.sock);
	g_atomic_int_set (socket, -1);

	return NULL;
}
示例#8
0
static GckObject *
lookup_public_key (GckObject *object,
                   GCancellable *cancellable,
                   GError **lerror)
{
	GckBuilder builder = GCK_BUILDER_INIT;
	gulong attr_types[] = { CKA_ID };
	GckAttributes *attrs;
	GError *error = NULL;
	GckSession *session;
	GckObject *result;
	const GckAttribute *id;
	GList *objects;

	attrs = gck_object_cache_lookup (object, attr_types, G_N_ELEMENTS (attr_types),
	                                 cancellable, &error);
	if (error != NULL) {
		_gcr_debug ("couldn't load private key id: %s", error->message);
		g_propagate_error (lerror, error);
		return NULL;
	}

	id = gck_attributes_find (attrs, CKA_ID);
	if (id == NULL || gck_attribute_is_invalid (id)) {
		gck_attributes_unref (attrs);
		_gcr_debug ("couldn't load private key id");
		g_set_error_literal (lerror, GCK_ERROR, CKR_ATTRIBUTE_TYPE_INVALID,
		                     gck_message_from_rv (CKR_ATTRIBUTE_TYPE_INVALID));
		return NULL;
	}

	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_PUBLIC_KEY);
	gck_builder_add_attribute (&builder, id);
	gck_attributes_unref (attrs);

	session = gck_object_get_session (object);
	objects = gck_session_find_objects (session, gck_builder_end (&builder), cancellable, &error);
	g_object_unref (session);

	if (error != NULL) {
		_gcr_debug ("couldn't lookup public key: %s", error->message);
		g_propagate_error (lerror, error);
		return NULL;
	}

	if (!objects)
		return NULL;

	result = g_object_ref (objects->data);
	gck_list_unref_free (objects);

	return result;
}
void
gkd_secret_objects_foreach_collection (GkdSecretObjects *self,
				       const gchar *caller,
				       GkdSecretObjectsForeach callback,
				       gpointer user_data)
{
	GckBuilder builder = GCK_BUILDER_INIT;
	GckSession *session;
	GError *error = NULL;
	GList *collections, *l;
	gpointer identifier;
	gsize n_identifier;
	gchar *path;

	g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
	g_return_if_fail (callback);

	/* The session we're using to access the object */
	if (caller == NULL) {
		session = gkd_secret_service_internal_pkcs11_session (self->service);
	} else {
		session = gkd_secret_service_get_pkcs11_session (self->service, caller);
	}

	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_COLLECTION);

	collections = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);

	if (error != NULL) {
		g_warning ("couldn't lookup collections: %s", egg_error_message (error));
		g_clear_error (&error);
		return;
	}

	for (l = collections; l; l = g_list_next (l)) {

		identifier = gck_object_get_data (l->data, CKA_ID, NULL, &n_identifier, &error);
		if (identifier == NULL) {
			g_warning ("couldn't get collection identifier: %s", egg_error_message (error));
			g_clear_error (&error);
			continue;
		}

		path = gkd_secret_util_build_path (SECRET_COLLECTION_PREFIX, identifier, n_identifier);
		g_free (identifier);

		(callback) (self, path, l->data, user_data);
		g_free (path);
	}

	gck_list_unref_free (collections);
}
示例#10
0
gboolean
gkd_secret_lock_all (GckSession *session,
                     DBusError *derr)
{
	GckBuilder builder = GCK_BUILDER_INIT;
	GError *error = NULL;
	GList *objects, *l;

	/* Lock all the main collections */
	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_CREDENTIAL);
	gck_builder_add_boolean (&builder, CKA_GNOME_TRANSIENT, TRUE);

	objects = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);
	if (error != NULL) {
		g_warning ("couldn't search for credential objects: %s", egg_error_message (error));
		dbus_set_error (derr, DBUS_ERROR_FAILED, "Couldn't lock service");
		g_clear_error (&error);
		return FALSE;
	}

	for (l = objects; l; l = g_list_next (l)) {
		if (!gck_object_destroy (l->data, NULL, &error)) {
			g_warning ("couldn't destroy credential object: %s", egg_error_message (error));
			g_clear_error (&error);
		}
	}

	/* Now delete all session objects */
	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
	gck_builder_add_string (&builder, CKA_G_COLLECTION, "session");

	objects = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);
	if (error != NULL) {
		g_warning ("couldn't search for session items: %s", egg_error_message (error));
		dbus_set_error (derr, DBUS_ERROR_FAILED, "Couldn't lock service");
		g_clear_error (&error);
		return FALSE;
	}

	for (l = objects; l; l = g_list_next (l)) {
		if (!gck_object_destroy (l->data, NULL, &error)) {
			g_warning ("couldn't destroy session item: %s", egg_error_message (error));
			g_clear_error (&error);
		}
	}

	gck_list_unref_free (objects);
	return TRUE;
}
示例#11
0
gboolean
gkd_ssh_agent_initialize_with_module (GckModule *module)
{
	GckSession *session = NULL;
	GList *slots, *l;
	GArray *mechs;
	GError *error = NULL;

	g_assert (GCK_IS_MODULE (module));

	/* Find a good slot for our session keys */
	slots = gck_module_get_slots (module, TRUE);
	for (l = slots; session == NULL && l; l = g_list_next (l)) {

		/* Check that it has the mechanisms we need */
		mechs = gck_slot_get_mechanisms (l->data);
		if (gck_mechanisms_check (mechs, CKM_RSA_PKCS, CKM_DSA, GCK_INVALID)) {

			/* Try and open a session */
			session = gck_slot_open_session (l->data, GCK_SESSION_AUTHENTICATE, NULL, &error);
			if (!session) {
				g_warning ("couldn't create pkcs#11 session: %s", egg_error_message (error));
				g_clear_error (&error);
			}
		}

		g_array_unref (mechs);
	}

	gck_list_unref_free (slots);

	if (!session) {
		g_warning ("couldn't select a usable pkcs#11 slot for the ssh agent to use");
		return FALSE;
	}

	g_assert (!pkcs11_modules);
	pkcs11_modules = g_list_append (NULL, g_object_ref (module));

	pkcs11_main_mutex = g_new0 (GMutex, 1);
	g_mutex_init (pkcs11_main_mutex);
	pkcs11_main_cond = g_new0 (GCond, 1);
	g_cond_init (pkcs11_main_cond);
	pkcs11_main_checked = FALSE;
	pkcs11_main_session = session;

	return TRUE;
}
示例#12
0
GckObject*
gkd_secret_objects_lookup_item (GkdSecretObjects *self, const gchar *caller,
				const gchar *path)
{
	GckBuilder builder = GCK_BUILDER_INIT;
	GckObject *object = NULL;
	GError *error = NULL;
	GList *objects;
	GckSession *session;
	gchar *collection;
	gchar *identifier;

	g_return_val_if_fail (GKD_SECRET_IS_OBJECTS (self), NULL);
	g_return_val_if_fail (caller, NULL);
	g_return_val_if_fail (path, NULL);

	if (!gkd_secret_util_parse_path (path, &collection, &identifier))
		return NULL;

	/* The session we're using to access the object */
	session = gkd_secret_service_get_pkcs11_session (self->service, caller);
	g_return_val_if_fail (session, NULL);

	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
	gck_builder_add_string (&builder, CKA_ID, identifier);
	gck_builder_add_string (&builder, CKA_G_COLLECTION, collection);

	objects = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);

	g_free (identifier);
	g_free (collection);

	if (error != NULL) {
		g_warning ("couldn't lookup item: %s: %s", path, egg_error_message (error));
		g_clear_error (&error);
	}

	if (objects)
		object = g_object_ref (objects->data);

	gck_list_unref_free (objects);
	return object;
}
示例#13
0
void
gkd_secret_objects_foreach_item (GkdSecretObjects *self,
				 const gchar *caller,
				 const gchar *base,
				 GkdSecretObjectsForeach callback,
				 gpointer user_data)
{
	GckBuilder builder = GCK_BUILDER_INIT;
	GckSession *session;
	GError *error = NULL;
	gchar *identifier;
	GList *items;

	g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
	g_return_if_fail (base != NULL);
	g_return_if_fail (callback != NULL);

	/* The session we're using to access the object */
	if (caller == NULL) {
		session = gkd_secret_service_internal_pkcs11_session (self->service);
	} else {
		session = gkd_secret_service_get_pkcs11_session (self->service, caller);
	}

	if (!gkd_secret_util_parse_path (base, &identifier, NULL))
		g_return_if_reached ();

	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
	gck_builder_add_string (&builder, CKA_G_COLLECTION, identifier);

	items = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);

	if (error == NULL) {
		objects_foreach_item (self, items, base, callback, user_data);

	} else {
		g_warning ("couldn't lookup items in '%s' collection: %s", identifier, egg_error_message (error));
		g_clear_error (&error);
	}

	gck_list_unref_free (items);
	g_free (identifier);
}
示例#14
0
gboolean
gkd_login_unlock (const gchar *master)
{
	GList *modules;
	gboolean result;

	/* We don't support null or empty master passwords */
	if (!master || !master[0])
		return FALSE;

	modules = module_instances ();

	result = unlock_or_create_login (modules, master);
	if (result == TRUE)
		init_pin_for_uninitialized_slots (modules, master);

	gck_list_unref_free (modules);
	return result;
}
示例#15
0
static void
on_parser_parsed (GcrParser *parser,
                  gpointer user_data)
{
	ImportClosure *closure = user_data;
	GcrParsed *parsed;
	GList *filtered;

	parsed = gcr_parser_get_parsed (parser);
	if (closure->num_parsed == 0) {
		closure->importers = gcr_importer_create_for_parsed (parsed);
	} else {
		filtered = gcr_importer_queue_and_filter_for_parsed (closure->importers, parsed);
		gck_list_unref_free (closure->importers);
		closure->importers = filtered;
	}

	closure->num_parsed++;
}
示例#16
0
gboolean
gkd_login_change_lock (const gchar *original, const gchar *master)
{
	GList *modules;
	gboolean result;

	/* We don't support null or empty master passwords */
	if (!master || !master[0])
		return FALSE;
	if (original == NULL)
		original = "";

	modules = module_instances ();

	result = change_or_create_login (modules, original, master);
	if (result == TRUE)
		set_pin_for_any_slots (modules, original, master);

	gck_list_unref_free (modules);
	return result;
}
示例#17
0
void
gkd_ssh_agent_uninitialize (void)
{
	gboolean ret;

	g_assert (pkcs11_main_mutex);
	ret = g_mutex_trylock (pkcs11_main_mutex);
	g_assert (ret);

		g_assert (GCK_IS_SESSION (pkcs11_main_session));
		g_assert (!pkcs11_main_checked);
		g_object_unref (pkcs11_main_session);
		pkcs11_main_session = NULL;

	g_mutex_unlock (pkcs11_main_mutex);
	g_mutex_clear (pkcs11_main_mutex);
	g_free (pkcs11_main_mutex);
	g_cond_clear (pkcs11_main_cond);
	g_free (pkcs11_main_cond);

	gck_list_unref_free (pkcs11_modules);
	pkcs11_modules = NULL;
}
示例#18
0
int
gkr_tool_import (int argc, char *argv[])
{
	GcrParser *parser;
	GError *error = NULL;
	GInputStream *input;
	ImportClosure *closure;
	GFile *file;
	gchar **imp;
	int ret = 0;
	GList *l;

	ret = gkr_tool_parse_options (&argc, &argv, import_entries);
	if (ret != 0)
		return ret;
	
	if(!import_files || !*import_files) {
		gkr_tool_handle_error (NULL, "specify files to import");
		return 2;
	}

	if (!gcr_pkcs11_initialize (NULL, &error)) {
		gkr_tool_handle_error (&error, "couldn't initialize pkcs11 modules");
		return 1;
	}

	parser = gcr_parser_new ();
	closure = g_new0 (ImportClosure, 1);
	g_signal_connect (parser, "parsed", G_CALLBACK (on_parser_parsed), closure);

	for (imp = import_files; *imp; ++imp) {
		file = g_file_new_for_commandline_arg (*imp);
		
		input = G_INPUT_STREAM (g_file_read (file, NULL, &error));
		g_object_unref (file);
		if (input == NULL) {
			gkr_tool_handle_error (&error, "couldn't read file: %s", *imp);
			ret = 1;

		} else {
			if (!gcr_parser_parse_stream (parser, input, NULL, &error)) {
				if (error->code != GCR_ERROR_CANCELLED)
					gkr_tool_handle_error (&error, "couldn't parse: %s", *imp);
				ret = 1;
			}

			g_object_unref (input);
		}
	}

	if (closure->importers == NULL) {
		gkr_tool_handle_error (NULL, "couldn't find any place to import files");
		ret = 1;
	}

	for (l = closure->importers; l != NULL; l = g_list_next (l)) {
		if (gcr_importer_import (l->data, NULL, &error)) {
			if (!gkr_tool_mode_quiet)
				imported_display (l->data);
		} else {
			if (error->code != GCR_ERROR_CANCELLED)
				gkr_tool_handle_error (&error, "couldn't import");
			ret = 1;
		}
	}

	gck_list_unref_free (closure->importers);
	g_free (closure);

	g_object_unref (parser);
	return ret;
}
示例#19
0
gboolean
gkd_secret_objects_handle_search_items (GkdSecretObjects *self,
					GDBusMethodInvocation *invocation,
					GVariant *attributes,
					const gchar *base,
					gboolean separate_locked)
{
	GckBuilder builder = GCK_BUILDER_INIT;
	GckObject *search;
	GckSession *session;
	GError *error = NULL;
	gchar *identifier;
	gpointer data;
	gsize n_data;
	GList *locked, *unlocked;
	GList *items;
	GVariantBuilder result;

	if (!gkd_secret_property_parse_fields (attributes, &builder)) {
		gck_builder_clear (&builder);
		g_dbus_method_invocation_return_error_literal (invocation,
							       G_DBUS_ERROR,
							       G_DBUS_ERROR_FAILED,
							       "Invalid data in attributes argument");
		return TRUE;
	}

	if (base != NULL) {
		if (!gkd_secret_util_parse_path (base, &identifier, NULL))
			g_return_val_if_reached (FALSE);
		gck_builder_add_string (&builder, CKA_G_COLLECTION, identifier);
		g_free (identifier);
	}

	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_SEARCH);
	gck_builder_add_boolean (&builder, CKA_TOKEN, FALSE);

	/* The session we're using to access the object */
	session = gkd_secret_service_get_pkcs11_session (self->service, g_dbus_method_invocation_get_sender (invocation));
	g_return_val_if_fail (session, FALSE);

	/* Create the search object */
	search = gck_session_create_object (session, gck_builder_end (&builder), NULL, &error);

	if (error != NULL) {
		g_dbus_method_invocation_return_error (invocation,
						       G_DBUS_ERROR,
						       G_DBUS_ERROR_FAILED,
						       "Couldn't search for items: %s",
						       egg_error_message (error));
		g_clear_error (&error);
		return TRUE;
	}

	/* Get the matched item handles, and delete the search object */
	data = gck_object_get_data (search, CKA_G_MATCHED, NULL, &n_data, &error);
	gck_object_destroy (search, NULL, NULL);
	g_object_unref (search);

	if (error != NULL) {
		g_dbus_method_invocation_return_error (invocation,
						       G_DBUS_ERROR,
						       G_DBUS_ERROR_FAILED,
						       "Couldn't retrieve matched items: %s",
						       egg_error_message (error));
		g_clear_error (&error);
		return TRUE;
	}

	/* Build a list of object handles */
	items = gck_objects_from_handle_array (session, data, n_data / sizeof (CK_OBJECT_HANDLE));
	g_free (data);

	/* Filter out the locked items */
	if (separate_locked) {
		GVariant *unlocked_variant, *locked_variant;

		item_cleanup_search_results (session, items, &locked, &unlocked);

		g_variant_builder_init (&result, G_VARIANT_TYPE ("ao"));
		objects_foreach_item (self, unlocked, NULL, on_object_path_append_to_builder, &result);
		unlocked_variant = g_variant_builder_end (&result);

		g_variant_builder_init (&result, G_VARIANT_TYPE ("ao"));
		objects_foreach_item (self, locked, NULL, on_object_path_append_to_builder, &result);
		locked_variant = g_variant_builder_end (&result);

		g_list_free (locked);
		g_list_free (unlocked);

		g_dbus_method_invocation_return_value (invocation,
						       g_variant_new ("(@ao@ao)",
								      unlocked_variant,
								      locked_variant));
	} else {
		g_variant_builder_init (&result, G_VARIANT_TYPE ("ao"));
		objects_foreach_item (self, items, NULL, on_object_path_append_to_builder, &result);

		g_dbus_method_invocation_return_value (invocation,
						       g_variant_new ("(@ao)", g_variant_builder_end (&result)));
	}

	gck_list_unref_free (items);

	return TRUE;
}