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;
}
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;
}
static gboolean
item_method_delete (GkdExportedItem *skeleton,
		    GDBusMethodInvocation *invocation,
		    GkdSecretObjects *self)
{
	GError *error = NULL;
	gchar *collection_path;
	gchar *item_path;
	GckObject *collection;
	GckObject *object;

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

	collection_path = collection_path_for_item (object);
	item_path = object_path_for_item (NULL, object);

	if (gck_object_destroy (object, NULL, &error)) {
		collection = gkd_secret_objects_lookup_collection (self, NULL, collection_path);
		if (collection != NULL) {
			gkd_secret_objects_emit_item_deleted (self, collection, item_path);
			g_object_unref (collection);
		}

		/* No prompt necessary */
		gkd_exported_item_complete_delete (skeleton, invocation, "/");

	} else {
		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 delete a locked item");
		else
			g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
							       G_DBUS_ERROR_FAILED,
							       "Couldn't delete collection: %s",
							       egg_error_message (error));

		g_clear_error (&error);
	}

	g_free (collection_path);
	g_free (item_path);
	g_object_unref (object);

	return TRUE;
}
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_delete (GkdExportedCollection *skeleton,
			  GDBusMethodInvocation *invocation,
			  GkdSecretObjects *self)
{
	GError *error = NULL;
	gchar *path;
	GckObject *object;

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

	path = object_path_for_collection (object);
	g_return_val_if_fail (path != NULL, FALSE);

	if (!gck_object_destroy (object, NULL, &error)) {
		g_dbus_method_invocation_return_error (invocation,
						       G_DBUS_ERROR,
						       G_DBUS_ERROR_FAILED,
						       "Couldn't delete collection: %s",
						       egg_error_message (error));
		g_clear_error (&error);
		goto cleanup;
	}

	/* Notify the callers that a collection was deleted */
	gkd_secret_service_emit_collection_deleted (self->service, path);
	gkd_exported_collection_complete_delete (skeleton, invocation, "/");

 cleanup:
	g_free (path);
	g_object_unref (object);

	return TRUE;
}
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;
}
Exemple #8
0
static gboolean
change_or_create_login (GList *modules, const gchar *original, const gchar *master)
{
	GError *error = NULL;
	GckSession *session;
	GckObject *login = NULL;
	GckObject *ocred = NULL;
	GckObject *mcred = NULL;
	gboolean success = FALSE;
	GckAttributes *atts;

	g_return_val_if_fail (original, FALSE);
	g_return_val_if_fail (master, FALSE);

	/* Find the login object */
	session = lookup_login_session (modules);
	login = lookup_login_keyring (session);

	/* Create the new credential we'll be changing to */
	mcred = create_credential (session, NULL, master, &error);
	if (mcred == NULL) {
		g_warning ("couldn't create new login credential: %s", egg_error_message (error));
		g_clear_error (&error);

	/* Create original credentials */
	} else if (login) {
		ocred = create_credential (session, login, original, &error);
		if (ocred == NULL) {
			if (g_error_matches (error, GCK_ERROR, CKR_PIN_INCORRECT)) {
				g_message ("couldn't change login master password, "
				           "original password was wrong: %s",
				           egg_error_message (error));
			} else {
				g_warning ("couldn't create original login credential: %s",
				           egg_error_message (error));
			}
			g_clear_error (&error);
		}
	}

	/* No keyring? try to create */
	if (!login && mcred) {
		login = create_login_keyring (session, mcred, &error);
		if (login == NULL) {
			g_warning ("couldn't create login keyring: %s", egg_error_message (error));
			g_clear_error (&error);
		} else {
			success = TRUE;
		}

	/* Change the master password */
	} else if (login && ocred && mcred) {
		atts = gck_attributes_new ();
		gck_attributes_add_ulong (atts, CKA_G_CREDENTIAL, gck_object_get_handle (mcred));
		if (!gck_object_set (login, atts, NULL, &error)) {
			g_warning ("couldn't change login master password: %s", egg_error_message (error));
			g_clear_error (&error);
		} else {
			success = TRUE;
		}
		gck_attributes_unref (atts);
	}

	if (ocred) {
		gck_object_destroy (ocred, NULL, NULL);
		g_object_unref (ocred);
	}
	if (mcred)
		g_object_unref (mcred);
	if (login)
		g_object_unref (login);
	if (session)
		g_object_unref (session);

	return success;
}