static gboolean
service_method_change_with_master_password (GkdExportedInternal *skeleton,
					    GDBusMethodInvocation *invocation,
					    gchar *path,
					    GVariant *original_variant,
					    GVariant *master_variant,
					    GkdSecretService *self)
{
	GkdSecretSecret *original, *master;
	GckObject *collection;
	GError *error = NULL;
	const gchar *sender;

	sender = g_dbus_method_invocation_get_sender (invocation);

	/* Parse the incoming message */
	original = gkd_secret_secret_parse (self, sender,
					    original_variant, &error);
	if (original == NULL) {
		g_dbus_method_invocation_take_error (invocation, error);
		return TRUE;
	}

	master = gkd_secret_secret_parse (self, sender,
					  master_variant, &error);
	if (master == NULL) {
		g_dbus_method_invocation_take_error (invocation, error);
		return TRUE;
	}

	/* Make sure we have such a collection */
	collection = gkd_secret_objects_lookup_collection (self->objects, sender,
							   path);

	/* No such collection */
	if (collection == NULL) {
	  g_dbus_method_invocation_return_error_literal (invocation, GKD_SECRET_ERROR,
							 GKD_SECRET_ERROR_NO_SUCH_OBJECT,
							 "The collection does not exist");
	}

	/* Success */
	else if (gkd_secret_change_with_secrets (collection, NULL, original, master, &error))
		gkd_exported_internal_complete_change_with_master_password
			(skeleton, invocation);

	/* Failure */
	else
		gkd_secret_propagate_error (invocation, "Couldn't change collection password", error);

	gkd_secret_secret_free (original);
	gkd_secret_secret_free (master);

	if (collection)
		g_object_unref (collection);

	return TRUE;
}
static DBusMessage*
service_method_change_with_master_password (GkdSecretService *self, DBusMessage *message)
{
	DBusError derr = DBUS_ERROR_INIT;
	GkdSecretSecret *original, *master;
	GckObject *collection;
	DBusMessageIter iter;
	DBusMessage *reply;
	GError *error = NULL;
	const gchar *path;

	/* Parse the incoming message */
	if (!dbus_message_has_signature (message, "o(oayays)(oayays)"))
		return NULL;
	if (!dbus_message_iter_init (message, &iter))
		g_return_val_if_reached (NULL);
	dbus_message_iter_get_basic (&iter, &path);
	dbus_message_iter_next (&iter);
	original = gkd_secret_secret_parse (self, message, &iter, &derr);
	if (original == NULL)
		return gkd_secret_error_to_reply (message, &derr);
	dbus_message_iter_next (&iter);
	master = gkd_secret_secret_parse (self, message, &iter, &derr);
	if (master == NULL) {
		gkd_secret_secret_free (original);
		return gkd_secret_error_to_reply (message, &derr);
	}

	/* Make sure we have such a collection */
	collection = gkd_secret_objects_lookup_collection (self->objects,
	                                                   dbus_message_get_sender (message),
	                                                   path);

	/* No such collection */
	if (collection == NULL)
		reply = dbus_message_new_error (message, SECRET_ERROR_NO_SUCH_OBJECT,
		                                "The collection does not exist");

	/* Success */
	else if (gkd_secret_change_with_secrets (collection, NULL, original, master, &error))
		reply = dbus_message_new_method_return (message);

	/* Failure */
	else
		reply = gkd_secret_propagate_error (message, "Couldn't change collection password", error);

	gkd_secret_secret_free (original);
	gkd_secret_secret_free (master);

	if (collection)
		g_object_unref (collection);

	return reply;
}
static void
gkd_secret_create_prompt_ready (GkdSecretPrompt *prompt)
{
	GkdSecretCreate *self = GKD_SECRET_CREATE (prompt);
	GkdSecretSecret *master;

	if (!gku_prompt_has_response (GKU_PROMPT (prompt))) {

		/* Does the alias exist? */
		if (locate_alias_collection_if_exists (self))
			unlock_or_complete_this_prompt (self);

		/* Otherwise we're going to prompt */
		else
			prepare_create_prompt (self);

		return;
	}

	/* Already prompted, create collection */
	g_return_if_fail (gku_prompt_get_response (GKU_PROMPT (prompt)) == GKU_RESPONSE_OK);
	master = gkd_secret_prompt_get_secret (prompt, "password");

	if (master && create_collection_with_secret (self, master))
		gkd_secret_prompt_complete (prompt);
	else
		gkd_secret_prompt_dismiss (prompt);

	gkd_secret_secret_free (master);
}
gboolean
gkd_secret_objects_handle_get_secrets (GkdSecretObjects *self,
				       GDBusMethodInvocation *invocation,
				       const gchar **paths,
				       const gchar *session_path)
{
	GkdSecretSession *session;
	GkdSecretSecret *secret;
	GckObject *item;
	const char *caller;
	int i;
	GVariantBuilder builder;
	GError *error = NULL;

	caller = g_dbus_method_invocation_get_sender (invocation);
	session = gkd_secret_service_lookup_session (self->service, session_path, caller);
	if (session == NULL) {
		g_dbus_method_invocation_return_error_literal (invocation, GKD_SECRET_ERROR,
							       GKD_SECRET_ERROR_NO_SESSION,
							       "The session does not exist");
		return TRUE;
	}

	g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{o(oayays)}"));

	for (i = 0; paths[i] != NULL; ++i) {

		/* Try to find the item, if it doesn't exist, just ignore */
		item = gkd_secret_objects_lookup_item (self, caller, paths[i]);
		if (!item)
			continue;

		secret = gkd_secret_session_get_item_secret (session, item, &error);
		g_object_unref (item);

		if (secret == NULL) {
			/* We ignore is locked, and just leave out from response */
			if (g_error_matches (error, GKD_SECRET_ERROR, GKD_SECRET_ERROR_IS_LOCKED)) {
				g_clear_error (&error);
				continue;

			/* All other errors stop the operation */
			} else {
				g_dbus_method_invocation_take_error (invocation, error);
				return TRUE;
			}
		}

		g_variant_builder_add (&builder, "{o@(oayays)}", paths[i], gkd_secret_secret_append (secret));
		gkd_secret_secret_free (secret);
	}

	g_dbus_method_invocation_return_value (invocation,
					       g_variant_new ("(@a{o(oayays)})", g_variant_builder_end (&builder)));
	return TRUE;
}
static gboolean
service_method_create_with_master_password (GkdExportedInternal *skeleton,
					    GDBusMethodInvocation *invocation,
					    GVariant *attributes,
					    GVariant *master,
					    GkdSecretService *self)
{
	GckBuilder builder = GCK_BUILDER_INIT;
	GkdSecretSecret *secret = NULL;
	GckAttributes *attrs = NULL;
	GError *error = NULL;
	gchar *path;
	const gchar *caller;

	if (!gkd_secret_property_parse_all (attributes, SECRET_COLLECTION_INTERFACE, &builder)) {
		gck_builder_clear (&builder);
		g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR,
							       G_DBUS_ERROR_INVALID_ARGS,
							       "Invalid properties argument");
		return TRUE;
	}

	caller = g_dbus_method_invocation_get_sender (invocation);
	secret = gkd_secret_secret_parse (self,
					  caller,
					  master, &error);
	if (secret == NULL) {
		gck_builder_clear (&builder);
		g_dbus_method_invocation_take_error (invocation, error);
		return TRUE;
	}

	gck_builder_add_boolean (&builder, CKA_TOKEN, TRUE);
	attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
	path = gkd_secret_create_with_secret (attrs, secret, &error);
	gck_attributes_unref (attrs);
	gkd_secret_secret_free (secret);

	if (path == NULL) {
		gkd_secret_propagate_error (invocation, "Couldn't create collection", error);
		return TRUE;
	}

	/* Notify the callers that a collection was created */
        g_message ("emit collection_Created");
	gkd_secret_service_emit_collection_created (self, path);

	gkd_exported_internal_complete_create_with_master_password
		(skeleton, invocation, path);
	g_free (path);

	return TRUE;
}
static void
gkd_secret_create_finalize (GObject *obj)
{
    GkdSecretCreate *self = GKD_SECRET_CREATE (obj);

    gkd_secret_secret_free (self->master);
    gck_attributes_unref (self->attributes);
    g_free (self->result_path);
    g_free (self->alias);

    G_OBJECT_CLASS (gkd_secret_create_parent_class)->finalize (obj);
}
static DBusMessage*
service_method_create_with_master_password (GkdSecretService *self, DBusMessage *message)
{
	GckBuilder builder = GCK_BUILDER_INIT;
	DBusError derr = DBUS_ERROR_INIT;
	DBusMessageIter iter, array;
	DBusMessage *reply = NULL;
	GkdSecretSecret *secret = NULL;
	GckAttributes *attrs = NULL;
	GError *error = NULL;
	gchar *path;

	/* Parse the incoming message */
	if (!dbus_message_has_signature (message, "a{sv}(oayays)"))
		return NULL;
	if (!dbus_message_iter_init (message, &iter))
		g_return_val_if_reached (NULL);
	dbus_message_iter_recurse (&iter, &array);
	if (!gkd_secret_property_parse_all (&array, SECRET_COLLECTION_INTERFACE, &builder)) {
		gck_builder_clear (&builder);
		return dbus_message_new_error (message, DBUS_ERROR_INVALID_ARGS,
		                               "Invalid properties argument");
	}
	dbus_message_iter_next (&iter);
	secret = gkd_secret_secret_parse (self, message, &iter, &derr);
	if (secret == NULL) {
		gck_builder_clear (&builder);
		return gkd_secret_error_to_reply (message, &derr);
	}

	gck_builder_add_boolean (&builder, CKA_TOKEN, TRUE);
	attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
	path = gkd_secret_create_with_secret (attrs, secret, &error);
	gck_attributes_unref (attrs);
	gkd_secret_secret_free (secret);

	if (path == NULL)
		return gkd_secret_propagate_error (message, "Couldn't create collection", error);

	/* Notify the callers that a collection was created */
	gkd_secret_service_emit_collection_created (self, path);

	reply = dbus_message_new_method_return (message);
	dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
	g_free (path);

	return reply;
}
static void
gkd_secret_exchange_finalize (GObject *obj)
{
	GkdSecretExchange *self = GKD_SECRET_EXCHANGE (obj);

	if (self->service) {
		g_object_remove_weak_pointer (G_OBJECT (self->service),
		                              (gpointer*)&(self->service));
		self->service = NULL;
	}

	g_clear_object (&self->session);
	gkd_secret_secret_free (self->last_secret);
	g_free (self->caller);

	G_OBJECT_CLASS (gkd_secret_exchange_parent_class)->finalize (obj);
}
static DBusMessage*
service_method_create_with_master_password (GkdSecretService *self, DBusMessage *message)
{
	DBusError derr = DBUS_ERROR_INIT;
	DBusMessageIter iter, array;
	DBusMessage *reply = NULL;
	GkdSecretSecret *secret = NULL;
	GckAttributes *attrs = NULL;
	gchar *path;

	/* Parse the incoming message */
	if (!dbus_message_has_signature (message, "a{sv}(oayays)"))
		return NULL;
	if (!dbus_message_iter_init (message, &iter))
		g_return_val_if_reached (NULL);
	attrs = gck_attributes_new ();
	dbus_message_iter_recurse (&iter, &array);
	if (!gkd_secret_property_parse_all (&array, SECRET_COLLECTION_INTERFACE, attrs)) {
		gck_attributes_unref (attrs);
		return dbus_message_new_error (message, DBUS_ERROR_INVALID_ARGS,
		                               "Invalid properties argument");
	}
	dbus_message_iter_next (&iter);
	secret = gkd_secret_secret_parse (self, message, &iter, &derr);
	if (secret == NULL) {
		gck_attributes_unref (attrs);
		return gkd_secret_error_to_reply (message, &derr);
	}

	gck_attributes_add_boolean (attrs, CKA_TOKEN, TRUE);
	path = gkd_secret_create_with_secret (attrs, secret, &derr);
	gck_attributes_unref (attrs);
	gkd_secret_secret_free (secret);

	if (path == NULL)
		return gkd_secret_error_to_reply (message, &derr);

	reply = dbus_message_new_method_return (message);
	dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
	g_free (path);

	return reply;
}
static gboolean
gkd_secret_exchange_decrypt_transport_data (GcrSecretExchange *exchange,
                                            GckAllocator allocator,
                                            const guchar *cipher_text,
                                            gsize n_cipher_text,
                                            const guchar *parameter,
                                            gsize n_parameter,
                                            guchar **plain_text,
                                            gsize *n_plain_text)
{
	GkdSecretExchange *self = GKD_SECRET_EXCHANGE (exchange);

	gkd_secret_secret_free (self->last_secret);

	self->last_secret = gkd_secret_secret_new (self->session,
	                                           parameter, n_parameter,
	                                           cipher_text, n_cipher_text);

	*plain_text = NULL;
	*n_plain_text = 0;
	return TRUE;
}
static gboolean
item_method_set_secret (GkdExportedItem *skeleton,
			GDBusMethodInvocation *invocation,
			GVariant *secret_variant,
			GkdSecretObjects *self)
{
	GkdSecretSecret *secret;
	const char *caller;
	GckObject *item;
	GError *error = NULL;

	item = secret_objects_lookup_gck_object_for_invocation (self, invocation);
	if (!item) {
		return TRUE;
	}

	caller = g_dbus_method_invocation_get_sender (invocation);
	secret = gkd_secret_secret_parse (self->service, caller, secret_variant, &error);
	if (error != NULL) {
		goto cleanup;
	}

	gkd_secret_session_set_item_secret (secret->session, item, secret, &error);
	gkd_secret_secret_free (secret);

	if (error != NULL) {
		goto cleanup;
	}

 cleanup:
	if (error != NULL) {
		g_dbus_method_invocation_take_error (invocation, error);
	} else {
		gkd_exported_item_complete_set_secret (skeleton, invocation);
	}

	g_object_unref (item);
	return TRUE;
}
static gboolean
item_method_get_secret (GkdExportedItem *skeleton,
			GDBusMethodInvocation *invocation,
			gchar *path,
			GkdSecretObjects *self)
{
	GkdSecretSession *session;
	GkdSecretSecret *secret;
	GckObject *item;
	GError *error = NULL;

	item = secret_objects_lookup_gck_object_for_invocation (self, invocation);
	if (!item) {
		return TRUE;
	}

	session = gkd_secret_service_lookup_session (self->service, path,
						     g_dbus_method_invocation_get_sender (invocation));
	if (session == NULL) {
		g_dbus_method_invocation_return_error_literal (invocation, GKD_SECRET_ERROR,
							       GKD_SECRET_ERROR_NO_SESSION,
							       "The session does not exist");
		goto cleanup;
	}

	secret = gkd_secret_session_get_item_secret (session, item, &error);
	if (secret == NULL) {
		g_dbus_method_invocation_take_error (invocation, error);
		goto cleanup;
	}

	gkd_exported_item_complete_get_secret (skeleton, invocation,
					       gkd_secret_secret_append (secret));
	gkd_secret_secret_free (secret);

 cleanup:
	g_object_unref (item);
	return TRUE;
}
static void
on_prompt_confirmation_complete (GObject *source,
                                 GAsyncResult *result,
                                 gpointer user_data)
{
    GkdSecretCreate *self = GKD_SECRET_CREATE (source);
    GkdSecretPrompt *prompt = GKD_SECRET_PROMPT (source);
    GError *error = NULL;

    self->confirmed = gcr_prompt_confirm_finish (GCR_PROMPT (source), result, &error);
    if (error != NULL) {
        gkd_secret_prompt_dismiss_with_error (prompt, error);
        g_error_free (error);
        return;
    }

    /* If not confirmed, then prompt again */
    if (!self->confirmed) {
        gkd_secret_secret_free (self->master);
        self->master = NULL;
    }

    perform_prompting (self);
}
static gboolean
collection_method_create_item (GkdExportedCollection *skeleton,
			       GDBusMethodInvocation *invocation,
			       GVariant *properties,
			       GVariant *secret_variant,
			       gboolean replace,
			       GkdSecretObjects *self)
{
	GckBuilder builder = GCK_BUILDER_INIT;
	GckSession *pkcs11_session = NULL;
	GkdSecretSecret *secret = NULL;
	GckAttributes *attrs = NULL;
	const GckAttribute *fields;
	GckObject *item = NULL;
	const gchar *base;
	GError *error = NULL;
	gchar *path = NULL;
	gchar *identifier;
	gboolean created = FALSE;
	GckObject *object;

	object = secret_objects_lookup_gck_object_for_invocation (self, invocation);
	if (!object) {
		return TRUE;
	}

	if (!gkd_secret_property_parse_all (properties, SECRET_ITEM_INTERFACE, &builder)) {
		g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR,
							       G_DBUS_ERROR_INVALID_ARGS,
							       "Invalid properties argument");
		goto cleanup;
	}

	base = g_dbus_method_invocation_get_object_path (invocation);
	secret = gkd_secret_secret_parse (self->service, g_dbus_method_invocation_get_sender (invocation),
					  secret_variant, &error);

	if (secret == NULL) {
		g_dbus_method_invocation_take_error (invocation, error);
		error = NULL;
		goto cleanup;
	}

	if (!gkd_secret_util_parse_path (base, &identifier, NULL))
		g_return_val_if_reached (FALSE);
	g_return_val_if_fail (identifier, FALSE);

	pkcs11_session = gck_object_get_session (object);
	g_return_val_if_fail (pkcs11_session, FALSE);

	attrs = gck_attributes_ref_sink (gck_builder_end (&builder));

	if (replace) {
		fields = gck_attributes_find (attrs, CKA_G_FIELDS);
		if (fields)
			item = collection_find_matching_item (self, pkcs11_session, identifier, fields);
	}

	/* Replace the item */
	if (item) {
		if (!gck_object_set (item, attrs, NULL, &error))
			goto cleanup;

	/* Create a new item */
	} else {
		gck_builder_add_all (&builder, attrs);
		gck_builder_add_string (&builder, CKA_G_COLLECTION, identifier);
		gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
		item = gck_session_create_object (pkcs11_session, gck_builder_end (&builder), NULL, &error);
		if (item == NULL)
			goto cleanup;
		created = TRUE;
	}

	/* Set the secret */
	if (!gkd_secret_session_set_item_secret (secret->session, item, secret, &error)) {
		if (created) /* If we created, then try to destroy on failure */
			gck_object_destroy (item, NULL, NULL);
		goto cleanup;
	}

	path = object_path_for_item (base, item);
	gkd_secret_objects_emit_item_created (self, object, path);

	gkd_exported_collection_complete_create_item (skeleton, invocation, path, "/");

cleanup:
	if (error) {
		if (g_error_matches (error, GCK_ERROR, CKR_USER_NOT_LOGGED_IN))
			g_dbus_method_invocation_return_error_literal (invocation, GKD_SECRET_ERROR,
								       GKD_SECRET_ERROR_IS_LOCKED,
								       "Cannot create an item in a locked collection");
		else
			g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
							       G_DBUS_ERROR_FAILED,
							       "Couldn't create item: %s",
							       egg_error_message (error));
		g_clear_error (&error);
	}

	gkd_secret_secret_free (secret);
	gck_attributes_unref (attrs);
	if (item)
		g_object_unref (item);
	if (pkcs11_session)
		g_object_unref (pkcs11_session);
	g_free (path);
	g_object_unref (object);

	return TRUE;
}