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;
}
Exemple #2
0
GNode *
_gcr_subject_public_key_load_finish (GAsyncResult *result,
                                     GError **error)
{
	GckAttributes *attributes;
	GSimpleAsyncResult *res;
	LoadClosure *closure;
	GNode *asn;

	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
	g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
	                      _gcr_subject_public_key_load_async), NULL);

	res = G_SIMPLE_ASYNC_RESULT (result);
	if (g_simple_async_result_propagate_error (res, error))
		return NULL;

	closure = g_simple_async_result_get_op_res_gpointer (res);
	attributes = gck_attributes_ref_sink (gck_builder_end (&closure->builder));
	asn = _gcr_subject_public_key_for_attributes (attributes);
	if (asn == NULL) {
		g_set_error_literal (error, GCK_ERROR, CKR_TEMPLATE_INCONSISTENT,
		                     _("Couldn't build public key"));
	}

	gck_attributes_unref (attributes);
	return asn;
}
Exemple #3
0
static void
gcr_key_renderer_class_init (GcrKeyRendererClass *klass)
{
	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
	GckBuilder builder = GCK_BUILDER_INIT;

	gcr_key_renderer_parent_class = g_type_class_peek_parent (klass);
	g_type_class_add_private (klass, sizeof (GcrKeyRendererPrivate));

	gobject_class->dispose = gcr_key_renderer_dispose;
	gobject_class->finalize = gcr_key_renderer_finalize;
	gobject_class->set_property = gcr_key_renderer_set_property;
	gobject_class->get_property = gcr_key_renderer_get_property;

	g_object_class_override_property (gobject_class, PROP_LABEL, "label");
	g_object_class_override_property (gobject_class, PROP_ATTRIBUTES, "attributes");

	g_object_class_install_property (gobject_class, PROP_OBJECT,
	            g_param_spec_object ("object", "Object", "Key Object", GCK_TYPE_OBJECT,
	                                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

	/* Register this as a view which can be loaded */
	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_PRIVATE_KEY);
	gcr_renderer_register (GCR_TYPE_KEY_RENDERER, gck_builder_end (&builder));
}
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;
}
Exemple #5
0
GNode *
_gcr_subject_public_key_load (GckObject *key,
                              GCancellable *cancellable,
                              GError **error)
{
	GckBuilder builder = GCK_BUILDER_INIT;
	GckAttributes *attributes;
	GNode *asn;

	g_return_val_if_fail (GCK_IS_OBJECT (key), NULL);
	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
	g_return_val_if_fail (error == NULL || *error == NULL, NULL);

	lookup_attributes (key, &builder);

	if (!check_attributes (&builder)) {
		if (!load_attributes (key, &builder, cancellable, error)) {
			gck_builder_clear (&builder);
			return NULL;
		}
	}

	attributes = gck_builder_end (&builder);
	asn = _gcr_subject_public_key_for_attributes (attributes);
	if (asn == NULL) {
		g_set_error_literal (error, GCK_ERROR, CKR_TEMPLATE_INCONSISTENT,
		                     _("Couldn't build public key"));
	}

	gck_attributes_unref (attributes);
	return asn;
}
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;
}
Exemple #7
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;
}
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;
}
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);
}
gchar*
gkd_secret_create_with_secret (GckAttributes *attrs,
                               GkdSecretSecret *master,
                               GError **error)
{
    GckBuilder builder = GCK_BUILDER_INIT;
    GckAttributes *atts;
    GckObject *cred;
    GckObject *collection;
    GckSession *session;
    gpointer identifier;
    gsize n_identifier;
    gboolean token;
    gchar *path;

    if (!gck_attributes_find_boolean (attrs, CKA_TOKEN, &token))
        token = FALSE;

    gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_CREDENTIAL);
    gck_builder_add_boolean (&builder, CKA_GNOME_TRANSIENT, TRUE);
    gck_builder_add_boolean (&builder, CKA_TOKEN, token);

    session = gkd_secret_session_get_pkcs11_session (master->session);
    g_return_val_if_fail (session, NULL);

    /* Create ourselves some credentials */
    atts = gck_attributes_ref_sink (gck_builder_end (&builder));
    cred = gkd_secret_session_create_credential (master->session, session,
            atts, master, error);
    gck_attributes_unref (atts);

    if (cred == NULL)
        return FALSE;

    collection = gkd_secret_create_with_credential (session, attrs, cred, error);

    g_object_unref (cred);

    if (collection == NULL)
        return FALSE;

    identifier = gck_object_get_data (collection, CKA_ID, NULL, &n_identifier, error);
    g_object_unref (collection);

    if (!identifier)
        return FALSE;

    path = gkd_secret_util_build_path (SECRET_COLLECTION_PREFIX, identifier, n_identifier);
    g_free (identifier);
    return path;
}
static gboolean
service_method_create_collection (GkdExportedService *skeleton,
				  GDBusMethodInvocation *invocation,
				  GVariant *properties,
				  gchar *alias,
				  GkdSecretService *self)
{
	GckBuilder builder = GCK_BUILDER_INIT;
	GckAttributes *attrs;
	GkdSecretCreate *create;
	const gchar *path;
	const char *caller;

	if (!gkd_secret_property_parse_all (properties, 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");
		return TRUE;
	}

	/* Empty alias is no alias */
	if (alias) {
		if (!alias[0]) {
			alias = NULL;
		} else if (!g_str_equal (alias, "default")) {
			gck_builder_clear (&builder);
			g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR,
								       G_DBUS_ERROR_NOT_SUPPORTED,
								       "Only the 'default' alias is supported");
			return TRUE;
		}
	}

	gck_builder_add_boolean (&builder, CKA_TOKEN, TRUE);
	attrs = gck_attributes_ref_sink (gck_builder_end (&builder));

	/* Create the prompt object, for the password */
	caller = g_dbus_method_invocation_get_sender (invocation);
	create = gkd_secret_create_new (self, caller, attrs, alias);
	gck_attributes_unref (attrs);

	path = gkd_secret_dispatch_get_object_path (GKD_SECRET_DISPATCH (create));
	gkd_secret_service_publish_dispatch (self, caller,
					     GKD_SECRET_DISPATCH (create));

	gkd_exported_service_complete_create_collection (skeleton, invocation,
							 "/", path);
	return TRUE;
}
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 gboolean
object_property_set (GkdSecretObjects *objects,
		     GckObject *object,
		     const gchar *prop_name,
		     GVariant *value,
		     GError **error_out)
{
	GckBuilder builder = GCK_BUILDER_INIT;
	GError *error = NULL;
	gulong attr_type;

	/* What type of property is it? */
	if (!gkd_secret_property_get_type (prop_name, &attr_type)) {
		g_set_error (error_out, G_DBUS_ERROR,
			     G_DBUS_ERROR_UNKNOWN_PROPERTY,
			     "Object does not have the '%s' property",
			     prop_name);
		return FALSE;
	}

	/* Retrieve the actual attribute value */
	if (!gkd_secret_property_parse_variant (value, prop_name, &builder)) {
		gck_builder_clear (&builder);
		g_set_error (error_out, G_DBUS_ERROR,
			     G_DBUS_ERROR_INVALID_ARGS,
			     "The property type or value was invalid: %s",
			     prop_name);
		return FALSE;
	}

	gck_object_set (object, gck_builder_end (&builder), NULL, &error);

	if (error != NULL) {
		if (g_error_matches (error, GCK_ERROR, CKR_USER_NOT_LOGGED_IN))
			g_set_error (error_out, GKD_SECRET_ERROR,
				     GKD_SECRET_ERROR_IS_LOCKED,
				     "Cannot set property on a locked object");
		else
			g_set_error (error_out, G_DBUS_ERROR,
				     G_DBUS_ERROR_FAILED,
				     "Couldn't set '%s' property: %s",
				     prop_name, egg_error_message (error));
		g_clear_error (&error);
		return FALSE;
	}

	return TRUE;
}
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;
}
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);
}
GckObject*
gkd_secret_create_with_credential (GckSession *session, GckAttributes *attrs,
                                   GckObject *cred, GError **error)
{
    GckBuilder builder = GCK_BUILDER_INIT;
    const GckAttribute *attr;
    gboolean token;

    gck_builder_add_ulong (&builder, CKA_G_CREDENTIAL, gck_object_get_handle (cred));
    gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_COLLECTION);

    attr = gck_attributes_find (attrs, CKA_LABEL);
    if (attr != NULL)
        gck_builder_add_attribute (&builder, attr);
    if (!gck_attributes_find_boolean (attrs, CKA_TOKEN, &token))
        token = FALSE;
    gck_builder_add_boolean (&builder, CKA_TOKEN, token);

    return gck_session_create_object (session, gck_builder_end (&builder), NULL, error);
}
static GckObject*
collection_find_matching_item (GkdSecretObjects *self,
			       GckSession *session,
			       const gchar *identifier,
			       const GckAttribute *fields)
{
	GckBuilder builder = GCK_BUILDER_INIT;
	GckObject *result = NULL;
	GError *error = NULL;
	GckObject *search;
	gpointer data;
	gsize n_data;

	/* Find items matching the collection and fields */
	gck_builder_add_attribute (&builder, fields);
	gck_builder_add_string (&builder, CKA_G_COLLECTION, identifier);
	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_SEARCH);
	gck_builder_add_boolean (&builder, CKA_TOKEN, FALSE);

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

	if (error != NULL) {
		g_warning ("couldn't search for matching item: %s", egg_error_message (error));
		g_clear_error (&error);
		return NULL;
	}

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

	if (n_data >= sizeof (CK_OBJECT_HANDLE))
		result = gck_object_from_handle (session, *((CK_OBJECT_HANDLE_PTR)data));

	g_free (data);
	return result;
}
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;
}
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;
}
static DBusMessage*
service_method_create_collection (GkdSecretService *self, DBusMessage *message)
{
	GckBuilder builder = GCK_BUILDER_INIT;
	DBusMessageIter iter, array;
	GckAttributes *attrs;
	GkdSecretCreate *create;
	DBusMessage *reply;
	const gchar *path;
	const gchar *alias;
	const char *caller;
	const gchar *coll;

	/* Parse the incoming message */
	if (!dbus_message_has_signature (message, "a{sv}s"))
		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_printf (message, DBUS_ERROR_INVALID_ARGS,
		                                      "Invalid properties");
	}
	if (!dbus_message_iter_next (&iter))
		g_return_val_if_reached (NULL);
	dbus_message_iter_get_basic (&iter, &alias);

	/* Empty alias is no alias */
	if (alias) {
		if (!alias[0]) {
			alias = NULL;
		} else if (!g_str_equal (alias, "default")) {
			gck_builder_clear (&builder);
			return dbus_message_new_error (message, DBUS_ERROR_NOT_SUPPORTED,
			                               "Only the 'default' alias is supported");
		}
	}

	gck_builder_add_boolean (&builder, CKA_TOKEN, TRUE);
	attrs = gck_attributes_ref_sink (gck_builder_end (&builder));

	/* Create the prompt object, for the password */
	caller = dbus_message_get_sender (message);
	create = gkd_secret_create_new (self, caller, attrs, alias);
	gck_attributes_unref (attrs);

	path = gkd_secret_dispatch_get_object_path (GKD_SECRET_DISPATCH (create));
	gkd_secret_service_publish_dispatch (self, caller,
	                                     GKD_SECRET_DISPATCH (create));

	coll = "/";
	reply = dbus_message_new_method_return (message);
	dbus_message_append_args (reply,
	                          DBUS_TYPE_OBJECT_PATH, &coll,
	                          DBUS_TYPE_OBJECT_PATH, &path,
	                          DBUS_TYPE_INVALID);

	g_object_unref (create);
	return reply;
}